package Yoseen;

import java.nio.charset.StandardCharsets;

import com.sun.jna.Callback;
import com.sun.jna.Structure;
import sun.misc.Unsafe;

public class YoseenData {
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    //PtzAction
    public static final byte PtzAction_Stop = 0;
    public static final byte PtzAction_MoveUp = 1;
    public static final byte PtzAction_MoveDown = 2;
    public static final byte PtzAction_MoveLeft = 3;
    public static final byte PtzAction_MoveRight = 4;
    public static final byte PtzAction_MoveLeftUp = 5;
    public static final byte PtzAction_MoveRightUp = 6;
    public static final byte PtzAction_MoveLeftDown = 7;
    public static final byte PtzAction_MoveRightDown = 8;
    public static final byte PtzAction_ZoomIn = 9;
    public static final byte PtzAction_ZoomOut = 10;
    public static final byte PtzAction_FocusFar = 11;
    public static final byte PtzAction_FocusNear = 12;
    public static final byte PtzAction_IrisOpen = 13;
    public static final byte PtzAction_IrisClose = 14;
    public static final byte PtzAction_PresetSet = 15;
    public static final byte PtzAction_PresetClear = 16;
    public static final byte PtzAction_PresetGoto = 17;
    public static final byte PtzAction_GetPTZ = 18;
    public static final byte PtzAction_SetPTZ = 19;
    public static final byte PtzAction_SwitchLightPowerOn = 20;
    public static final byte PtzAction_SwitchLightPowerOff = 21;
    public static final byte PtzAction_SwitchWiperPowerOn = 22;
    public static final byte PtzAction_SwitchWiperPowerOff = 23;
    public static final byte PtzAction_GetPan = 24;
    public static final byte PtzAction_SetPan = 25;
    public static final byte PtzAction_GetTilt = 26;
    public static final byte PtzAction_SetTilt = 27;
    public static final byte  PtzAction_GetZoom = 28;
    public static final byte PtzAction_SetZoom = 29;
    public static final byte PtzAction_B160_Backlight = 30;
    public static final byte PtzAction_B160_GetVersion = 31;
    public static final byte PtzAction_B160_W4R4 = 32;
    public static final byte PtzAction_DiaoCangSuiDong = 33;

    //////////////////////////////////////////////////////////////////////////////////////////////////////
    @Structure.FieldOrder(value = {"CameraAddr", "Username", "Password"})
    public static class YoseenLoginInfo extends Structure {
        public byte[] CameraAddr = new byte[128];            ///< IP
        public byte[] Username = new byte[32];               ///< 用户
        public byte[] Password = new byte[32];               ///< 密码

        public void setCameraAddr(String cameraAddr) {
            YoseenUtil.String2Bytes(cameraAddr, CameraAddr, 128);
        }

        public String toString() {
            return String.format("CameraAddr: %s\nUsername: %s\nPassword: %s",
                    new String(CameraAddr, StandardCharsets.US_ASCII),
                    new String(Username, StandardCharsets.US_ASCII),
                    new String(Password, StandardCharsets.US_ASCII));
        }
    }

    public interface YoseenPreviewCallback extends Callback {
        void callback(int errorCode, long dataFrame, long customData);
    }

    @Structure.FieldOrder(value = {"DataType", "Hwnd", "CustomCallback", "CustomData", "OutputWidth", "OutputHeight"})
    public static class YoseenPreviewInfo extends Structure {
        public long DataType;                               ///< xxxdatatype_video 视频流, xxxdatatype_temp 温度流
        public long Hwnd;                                   ///< 窗口句柄
        public YoseenPreviewCallback CustomCallback;        ///< 预览回调
        public long CustomData;                             ///< 用户数据

        public short OutputWidth;                            ///< 画面宽度
        public short OutputHeight;                           ///< 画面高度

        public String toString() {
            return String.format(
                    "DataType: %d\nHwnd: 0x%08x\nCustomCallback: %s\nCustomData: 0x%08x\nOutputWidth: %d\nOutputHeight: %d\n",
                    DataType, Hwnd, CustomCallback, CustomData, OutputWidth,
                    OutputHeight);
        }
    }

    @Structure.FieldOrder(value = {"CameraId", "CameraName", "CameraType", "FPAId", "HardwareId", "SoftwareId",
            "DataWidth", "DataHeight", "DataFps", "DataRatio", "SendRatio", "reserved"})
    public static class CameraBasicInfo extends Structure {
        public byte[] CameraId = new byte[32];
        public byte[] CameraName = new byte[32];
        public byte[] CameraType = new byte[16];

        public byte[] FPAId = new byte[32];
        public byte[] HardwareId = new byte[32];
        public byte[] SoftwareId = new byte[32];

        public short DataWidth;
        public short DataHeight;
        public short DataFps;

        public short DataRatio;
        public short SendRatio;

        public byte[] reserved = new byte[30];

        public String toString() {
            return String.format("CameraId: %s\nCameraName: %s\nCameraType: %s\n"
                            + "FPAId: %s\nHardwareId: %s\nSoftwareId: %s\n"
                            + "DataWidth: %d\nDataHeight: %d\nDataFps: %d\n"
                            + "DataRatio: %d\nSendRatio: %d",
                    new String(CameraId, StandardCharsets.US_ASCII), new String(CameraName, StandardCharsets.US_ASCII), new String(CameraType, StandardCharsets.US_ASCII),
                    new String(FPAId, StandardCharsets.US_ASCII), new String(HardwareId, StandardCharsets.US_ASCII), new String(SoftwareId, StandardCharsets.US_ASCII),
                    DataWidth, DataHeight, DataFps, DataRatio, SendRatio);
        }
    }

    @Structure.FieldOrder(value = {"UseStaticIp", "pad", "MulticastPort", "StaticIp", "SubnetMask", "Gateway",
            "MulticastIp", "MacAddr", "pad2", "Dns", "Dns2", "reserved"})
    public static class CameraNetworkInfo extends Structure {
        public byte UseStaticIp;
        public byte pad;
        public short MulticastPort;

        public int StaticIp;
        public int SubnetMask;
        public int Gateway;
        public int MulticastIp;
        public byte[] MacAddr = new byte[6];
        public byte[] pad2 = new byte[2];

        public int Dns;
        public int Dns2;
        public byte[] reserved = new byte[16];

        public String toString() {
            return String.format("UseStaticIp: %d\nStaticIp: %s\nSubnetMask: %s\n"
                            + "Gateway: %s\nDns: %s\nDns2: %s\nMacAddr: %02x:%02x:%02x:%02x:%02x:%02x",
                    UseStaticIp, YoseenUtil.IpInt2Str(StaticIp), YoseenUtil.IpInt2Str(SubnetMask),
                    YoseenUtil.IpInt2Str(Gateway), YoseenUtil.IpInt2Str(Dns), YoseenUtil.IpInt2Str(Dns2),
                    MacAddr[0], MacAddr[1], MacAddr[2], MacAddr[3], MacAddr[4], MacAddr[5]);
        }
    }

    @Structure.FieldOrder(value = {"AtmosphericTemperature", "RelativeHumidity", "Visibility", "RainfallIntensity", "SnowfallIntensity",
            "TargetDistance", "GlobalEmissivity", "InfraredWindowTrans", "TempOffset", "EnableAtmFix", "reserved"})
    public static class FixInfo extends Structure {
        public float AtmosphericTemperature;
        public float RelativeHumidity;
        public float Visibility;
        public float RainfallIntensity;
        public float SnowfallIntensity;
        public float TargetDistance;

        public float GlobalEmissivity;
        public float InfraredWindowTrans;
        public float TempOffset;
        public byte EnableAtmFix;
        public byte[] reserved = new byte[35];

        public String toString() {
            String s = String.format("AtmosphericTemperature: %.2f\nRelativeHumidity: %.2f\nVisibility: %.2f\n"
                            + "RainfallIntensity: %.2f\nSnowfallIntensity: %.2f\nTargetDistance :%.2f\n"
                            + "GlobalEmissivity: %.2f\nInfraredWindowTrans: %.2f\nTempOffset: %.2f\nEnableAtmFix: %d",
                    AtmosphericTemperature, RelativeHumidity, Visibility, RainfallIntensity, SnowfallIntensity,
                    TargetDistance, GlobalEmissivity, InfraredWindowTrans, TempOffset, EnableAtmFix);
            return s;
        }
    }

    @Structure.FieldOrder(value = {"EnableTvout", "PaletteType", "TvStdId", "Contrast", "Brightness", "Zoom",
            "XuiDisplayFlags", "Gain", "H264_Bitrate", "H264_GopSize", "reserved"})
    public static class TvoutInfo extends Structure {
        public byte EnableTvout;
        public byte PaletteType;
        public byte TvStdId;
        public byte Contrast;
        public byte Brightness;
        public byte Zoom;
        public short XuiDisplayFlags;
        public float Gain;
        public int H264_Bitrate;
        public short H264_GopSize;
        public byte[] reserved = new byte[22];

        public String toString() {
            return String.format("EnableTvout: %d\nPaletteType: %d\nTvStdId: %d\nContrast: %d\nBrightness: %d\nZoom: %d\n"
                            + "XuiDisplayFlags: 0x%04x\nGain: %.2f\nH264_Bitrate: %d\nH264_GopSize: %d",
                    EnableTvout, PaletteType, TvStdId, Contrast, Brightness, Zoom,
                    XuiDisplayFlags, Gain, H264_Bitrate, H264_GopSize);
        }
    }

    @Structure.FieldOrder(value = {"Type", "Data"})
    public static class Ctl extends Structure {
        //
        public static final short CtlType_RestartCamera = 4;
        public static final short CtlType_ManualFFC = 32;
        public static final short CtlType_FocusManual = 34;
        public static final short CtlType_FocusAuto = 35;
        public static final short CtlType_DisableFFC = 37;
        public static final short CtlType_FocusManual2 = 38;

        //
        public short Type;
        public byte[] Data = new byte[8];

        public void setManualFFC() {
            Type = CtlType_ManualFFC;
        }

        public void setFocusDelta(int focusDelta) {
            Type = CtlType_FocusManual;
            Data[0] = (byte) (focusDelta & 0x00ff);
            Data[1] = (byte) ((focusDelta >> 8) & 0x00ff);
        }

        public void setFocusInfo(int xmin, int ymin, int xmax, int ymax) {
            Type = CtlType_FocusAuto;
            Data[0] = (byte) (xmin & 0x00ff);
            Data[1] = (byte) ((xmin >> 8) & 0x00ff);
            Data[2] = (byte) (ymin & 0x00ff);
            Data[3] = (byte) ((ymin >> 8) & 0x00ff);

            Data[4] = (byte) (xmax & 0x00ff);
            Data[5] = (byte) ((xmax >> 8) & 0x00ff);
            Data[6] = (byte) (ymax & 0x00ff);
            Data[7] = (byte) ((ymax >> 8) & 0x00ff);
        }

        public String toString() {
            return String.format("Type: %d", Type);
        }
    }

    //
    public static class xxxptzcmd {
        public byte act;
        public byte arg;
        short pad;
        public int pan;
        public int tilt;
        public int zoom;
    }

    public static class CtlX {
        //
        static final int CtlX_GetTime = 0;
        static final int CtlX_SetTime = 1;
        static final int CtlX_GetGear = 2;
        static final int CtlX_SetGear = 3;
        static final int CtlX_AutoFocus = 4;

        //add20210607
        static final int CtlXType_ExecutePtz = 14;

        //
        public void makeReq_AutoFocus(long mem, int xmin, int ymin, int xmax, int ymax) {
            Unsafe unsafe = YoseenSDK.YoseenDevice.__unsafe;
            long p = mem;

            unsafe.putInt(p, CtlX_AutoFocus);
            p += 4;
            unsafe.putShort(p, (short) xmin);
            p += 2;
            unsafe.putShort(p, (short) ymin);
            p += 2;
            unsafe.putShort(p, (short) xmax);
            p += 2;
            unsafe.putShort(p, (short) ymax);
            p += 2;
        }

        public void makeReq_ExecutePtz(long mem, xxxptzcmd x) {
            Unsafe unsafe = YoseenSDK.YoseenDevice.__unsafe;
            long p = mem;

            //type
            unsafe.putInt(p, CtlXType_ExecutePtz);
            p += 4;

            //xxxptzcmd
            unsafe.putByte(p, x.act);
            p += 1;
            unsafe.putByte(p, x.arg);
            p += 3;
            unsafe.putInt(p, x.pan);
            p += 4;
            unsafe.putInt(p, x.tilt);
            p += 4;
            unsafe.putInt(p, x.zoom);
            p += 4;
        }

        public void makeResp_ExecutePtz(long mem, xxxptzcmd x) {
            Unsafe unsafe = YoseenSDK.YoseenDevice.__unsafe;
            long p = mem + 8;
            x.pan = unsafe.getInt(p);
            p += 4;
            x.tilt = unsafe.getInt(p);
            p += 4;
            x.zoom = unsafe.getInt(p);
            p += 4;
        }

    }

    @Structure.FieldOrder(value = {"Data"})
    public static class SerialPortData extends Structure {
        //0: dataSize, 1-31: data
        public byte[] Data = new byte[32];

        public String toString() {
            return String.format("size: %d", Data[0]);
        }
    }

    @Structure.FieldOrder(value = {"flags", "strech_type", "contrast", "brightness", "phe_stream", "phe_gain",
            "man_temp0", "man_temp1", "man_enable", "pad",
            "dde_level",
            "ct_type", "ct_temp0", "ct_temp1", "ct_color0", "ct_color1",
            "ck_lowDelta", "ck_lowPercent", "pad2",
            "hw_lowDelta", "hw_lowPercent", "reserved"})
    public static class strech_control extends Structure {
        //
        public static final int SCF_StrechType = 0x0001;        ///< 算法类型
        public static final int SCF_Gain = 0x0008;              ///< 增益
        public static final int SCF_Linear = 0x0010;            ///< 分段线性参数
        public static final int SCF_ClearStream = 0x0020;       ///< 清除流标志
        public static final int SCF_DDELevel = 0x0040;          ///< DDE等级

        //
        public static final int StrechType_PHE = 1;           ///< PHE
        public static final int StrechType_LINEAR = 2;        ///< LINEAR

        //
        public int flags;               ///< 标志
        public byte strech_type;        ///< 算法类型
        public byte contrast;
        public byte brightness;
        public byte phe_stream;
        public float phe_gain;              ///< 增益, [0.1, 10]

        //
        public short man_temp0;            ///< 手动温度0, 0.1C
        public short man_temp1;            ///< 手动温度1, 0.1C
        public byte man_enable;            ///< 手动温度
        public byte pad;

        public byte dde_level;              ///< DDE等级[0, 8]

        //
        public byte ct_type;                ///< 温度标记类型
        public short ct_temp0;                ///< 温度0, 0.1C
        public short ct_temp1;                ///< 温度1, 0.1C
        public int ct_color0;                ///< 颜色0
        public int ct_color1;                ///< 颜色1

        //ck20211113
        public short ck_lowDelta;           ///< 0.1C
        public short ck_lowPercent;         ///< %1

        public byte[] pad2 = new byte[5];

        //hw20211216
        public short hw_lowDelta;           ///< 0.1C
        public short hw_lowPercent;         ///< %1
        public byte[] reserved = new byte[21];

        public String toString() {
            return String.format("flags: %08x, strech_type: %d, contrast %d, brightness %d, gain %3.1f\n"
                            + "man_temp0, %d, man_temp1 %d, man_enable %d, \n" + "dde_level %d",
                    flags, strech_type, contrast, brightness, phe_gain,
                    man_temp0, man_temp1, man_enable, dde_level);
        }
    }

    @Structure.FieldOrder(value = {"ffh", "custom", "dfh", "dfd", "visiImage", "coverImage", "visiImageSize", "coverImageSize"})
    public static class TempFrameFile extends Structure {
        public static class ByReference extends TempFrameFile implements Structure.ByReference {
        }

        //
        public long ffh;
        public long custom;
        public long dfh;
        public long dfd;
        public long visiImage;
        public long coverImage;

        public int visiImageSize;
        public int coverImageSize;

        //
        public String toString() {
            return String.format("ffh: %08x\ncustom: %08x\ndfh: %08x\ndfd: %08x\nvisiImage: %08x\ncoverImage: %08x\nvisiImageSize: %d\ncoverImageSize: %d",
                    ffh, custom, dfh, dfd, visiImage, coverImage, visiImageSize, coverImageSize);
        }
    }

    @Structure.FieldOrder(value = {"Head", "Temp", "Com", "Bmp", "H264", "Prev"})
    public static class DataFrame extends Structure {
        public long Head;       ///< 温度数据头
        public long Temp;       ///< 温度数据
        public long Com;        ///<
        public long Bmp;        ///< 位图数据
        public long H264;       ///<
        public long Prev;       ///<

        public String toString() {
            return String.format("Head: %08x\nTemp: %08x\nCom: %08x\nBmp: %08x\nH264: %08x\nPrev: %08x",
                    Head, Temp, Com, Bmp, H264, Prev);
        }
    }

    @Structure.FieldOrder(value = {"alarmLevel", "maxX", "maxY", "minX", "minY", "max", "min", "avg"})
    public static class xxxresult extends Structure {
        public int alarmLevel;
        public short maxX;
        public short maxY;
        public short minX;
        public short minY;

        public float max;
        public float min;
        public float avg;
    }

    @Structure.FieldOrder(value = {"version", "width", "height", "shieldFlags", "LMOFlags", "pad"})
    public static class MeasureTemplateHead extends Structure {
        public int version;
        public short width;
        public short height;
        public int shieldFlags;
        public int LMOFlags;
        public byte[] pad = new byte[112];

        public String toString() {
            return "MeasureTemplateHead{" +
                    "version=" + version +
                    ", width=" + width +
                    ", height=" + height +
                    ", shieldFlags=" + shieldFlags +
                    ", lMOFlags=" + LMOFlags +
                    '}';
        }
    }

    @Structure.FieldOrder(value = {"Head", "ShieldArray", "GMO", "LMOArray"})
    public static class MeasureTemplate extends Structure {
        //测温模板头
        public MeasureTemplateHead Head = new MeasureTemplateHead();
        ///< 全局屏蔽区, 0-8个
        public xxxshield[] ShieldArray = (xxxshield[]) new xxxshield().toArray(8);
        ///< 全局测温对象
        public xxxmeasure GMO = new xxxmeasure();
        ///< 局部测温对象, 0-16个
        public xxxmeasure[] LMOArray = (xxxmeasure[]) new xxxmeasure().toArray(16);
    }

    @Structure.FieldOrder(value = {"GMR", "LMRArray"})
    public static class MeasureTemplateResult extends Structure {
        ///< 全局测温结果
        public xxxresult GMR = new xxxresult();
        ///< 局部测温结果, 0-16个
        public xxxresult[] LMRArray = (xxxresult[]) new xxxresult().toArray(16);
    }

    @Structure.FieldOrder(value = {"id", "pad", "xydata"})
    public static class xxxshield extends Structure {
        public byte id;
        public byte[] pad = new byte[3];
        public short[] xydata = new short[8];
    }

    @Structure.FieldOrder(value = {"id", "measuretype", "points", "emmi", "xydata", "alarmtype", "measureflags", "pad", "alarmdata"})
    public static class xxxmeasure extends Structure {
        public byte id;                     ///< 序号
        public byte measuretype;            ///< 类型
        public byte points;                 ///< 点数
        public byte emmi;                   ///< 发射率, 单位0.01
        public short[] xydata = new short[64];                ///< 点数据, x0,y0,x1,y1,...

        public byte alarmtype;               ///< 报警类型
        public byte measureflags;            ///< 测温标志
        public byte[] pad = new byte[2];
        public float[] alarmdata = new float[4];    ///< 报警温度值t0,t1,t2
    }

}
