using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using HalconDotNet;
using MvCamCtrl.NET;

namespace CodeLibrary
{
    partial class HIK : ClsCamera
    {
        /// <summary>
        /// 当前相机
        /// </summary>
        private MyCamera[] cameraCurr;
        /// <summary>
        /// 所有相机列表
        /// </summary>
        private MyCamera.MV_CC_DEVICE_INFO_LIST cameraAll;


        public override void Close(int index)
        {
            if (cameraCurr[index] != null)
            {
                _isOpen[index] = false;
                cameraCurr[index].MV_CC_CloseDevice_NET();
                cameraCurr[index].MV_CC_DestroyDevice_NET();
                cameraCurr[index] = null;
            }
        }
        public override void Close(string name)
        {
            int index = cameraName.FindIndex(s => s == name);
            if (index == -1)
            {
                _errInfo = "Not find";
                return;
            }
            if (cameraCurr[index] != null)
            {
                _isOpen[index] = false;
                cameraCurr[index].MV_CC_CloseDevice_NET();
                cameraCurr[index].MV_CC_DestroyDevice_NET();
                cameraCurr[index] = null;
            }
        }
        public override void CloseAll()
        {
            for (int i = 0; i < cameraCurr.Length; i++)
            {
                if (cameraCurr[i] != null)
                {
                    _isOpen[i] = false;
                    cameraCurr[i].MV_CC_CloseDevice_NET();
                    cameraCurr[i].MV_CC_DestroyDevice_NET();
                    cameraCurr[i] = null;
                }
            }
        }

        public override Bitmap GrabOne(int index)
        {
            if (cameraCurr[index] == null)
            {
                _errInfo = "Camera null";
                return null;
            }

            try
            {
                int rtn = cameraCurr[index].MV_CC_StartGrabbing_NET();
                if (rtn != MyCamera.MV_OK)
                {
                    _errInfo = "Can not grab one : " + rtn;
                    return null;
                }
                return ImageCapture(index);
                _errInfo = "OK";
                // return true;
            }
            catch (Exception ex)
            {
                _errInfo = ex.Message;
                return null;
            }
            finally
            {
                cameraCurr[index].MV_CC_StopGrabbing_NET();
            }
        }

        public override Bitmap GrabOne(string name)
        {
            int idx = Array.FindIndex(_name, s => s == name);
            if (idx == -1)
                return null;
            else
                return GrabOne(idx);
        }


        public override bool Load()
        {
            try
            {
                cameraAll = new MyCamera.MV_CC_DEVICE_INFO_LIST();
                int rtn = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref cameraAll);
                if (rtn != MyCamera.MV_OK)
                {
                    _errInfo = "Load failed";
                    return false;
                }

                cameraName = new List<string>();
                string s = "";
                for (int i = 0; i < cameraAll.nDeviceNum; i++)
                {
                    MyCamera.MV_CC_DEVICE_INFO device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(cameraAll.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));
                    if (device.nTLayerType == MyCamera.MV_GIGE_DEVICE)
                    {
                        IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(device.SpecialInfo.stGigEInfo, 0);
                        MyCamera.MV_GIGE_DEVICE_INFO gigeInfo = (MyCamera.MV_GIGE_DEVICE_INFO)Marshal.PtrToStructure(buffer, typeof(MyCamera.MV_GIGE_DEVICE_INFO));
                        s = "GigE:" + gigeInfo.chModelName + " (" + gigeInfo.chSerialNumber + ")";
                    }
                    else if (device.nTLayerType == MyCamera.MV_USB_DEVICE)
                    {
                        IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(device.SpecialInfo.stUsb3VInfo, 0);
                        MyCamera.MV_USB3_DEVICE_INFO usbInfo = (MyCamera.MV_USB3_DEVICE_INFO)Marshal.PtrToStructure(buffer, typeof(MyCamera.MV_USB3_DEVICE_INFO));
                        s = "USB:" + usbInfo.chModelName + " (" + usbInfo.chSerialNumber + ")";
                    }
                    cameraName.Add(s);
                }

                _name = cameraName.ToArray();
                _count = cameraName.Count;
                _isOpen = new bool[_count];
                _width = new int[_count];
                _height = new int[_count];
                cameraCurr = new MyCamera[_count];
                _errInfo = "OK";
                return true;
            }
            catch (Exception ex)
            {
                _errInfo = ex.Message;
                return false;
            }
        }

        public override bool Open(int index)
        {
            //   _index = index;
            if (index < 0 || index >= _count)
            {
                _errInfo = "Not find";
                return false;
            }
            if (cameraCurr[index] != null) Close(index);

            try
            {
                MyCamera.MV_CC_DEVICE_INFO device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(cameraAll.pDeviceInfo[index], typeof(MyCamera.MV_CC_DEVICE_INFO));
                cameraCurr[index] = new MyCamera();

                int nRet = cameraCurr[index].MV_CC_CreateDevice_NET(ref device);
                if (nRet != MyCamera.MV_OK) return false;
                nRet = cameraCurr[index].MV_CC_OpenDevice_NET();
                if (nRet != MyCamera.MV_OK)
                {
                    cameraCurr[index].MV_CC_DestroyDevice_NET();
                    _errInfo = "Can not open";
                    return false;
                }

                if (device.nTLayerType == MyCamera.MV_GIGE_DEVICE)
                {
                    int nPacketSize = cameraCurr[index].MV_CC_GetOptimalPacketSize_NET();
                    if (nPacketSize > 0) nRet = cameraCurr[index].MV_CC_SetIntValue_NET("GevSCPSPacketSize", (uint)nPacketSize);
                }
                //cameraCurr[index].MV_CC_SetEnumValue_NET("AcquisitionMode", 2);  //工作在连续模式
                cameraCurr[index].MV_CC_SetEnumValue_NET("TriggerMode", 0);  //连续模式
                MyCamera.MVCC_INTVALUE pstValue = new MyCamera.MVCC_INTVALUE();
                nRet = cameraCurr[index].MV_CC_GetWidth_NET(ref pstValue);
                _width[index] = (int)pstValue.nCurValue;
                nRet = cameraCurr[index].MV_CC_GetHeight_NET(ref pstValue);
                _height[index] = (int)pstValue.nCurValue;

                _isOpen[index] = true;
                _errInfo = "OK";
                return true;
            }
            catch (Exception ex)
            {
                HDLogUtil.error("打开相机出错:" + ex.ToString());
                _errInfo = ex.Message;
                return false;
            }
        }

        public override bool Open(string name)
        {
            int n = cameraName.FindIndex(s => s == name);
            if (n == -1)
            {
                _errInfo = name + " Not find";
                return false;
            }
            else
                return Open(n);
        }
        public override Bitmap GrabOneImage(string name)
        {
            int n = cameraName.FindIndex(s => s == name);
            if (n == -1)
            {
                _errInfo = name + " Not find";
                return null;
            }
            if (cameraCurr[n] != null)
            {
            }
            else
            {
                Open(name);
            }
            return GrabOne(name);

        }
        public override bool OpenAll()
        {
            bool rtn = true;
            for (int i = 0; i < cameraName.Count; i++)
            {
                rtn = Open(i);
                if (!rtn) break;
            }
            return rtn;
        }



        private Bitmap ImageCapture(int index)
        {
            MyCamera.MVCC_INTVALUE stParam = new MyCamera.MVCC_INTVALUE();
            int rtn = cameraCurr[index].MV_CC_GetIntValue_NET("PayloadSize", ref stParam);
            if (rtn != MyCamera.MV_OK) return null;
            uint dataSize = stParam.nCurValue;
            byte[] dataArr = new byte[dataSize];
            uint buffSize = dataSize * 3 + 2048;
            byte[] buffArr = new byte[buffSize];
            IntPtr pData = Marshal.UnsafeAddrOfPinnedArrayElement(dataArr, 0);
            MyCamera.MV_FRAME_OUT_INFO_EX stFrameInfo = new MyCamera.MV_FRAME_OUT_INFO_EX();
            rtn = cameraCurr[index].MV_CC_GetOneFrameTimeout_NET(pData, dataSize, ref stFrameInfo, 3000);
            if (rtn != MyCamera.MV_OK) return null;

            MyCamera.MvGvspPixelType enDstPixelType = stFrameInfo.enPixelType;
            switch (stFrameInfo.enPixelType)
            {
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed:
                    enDstPixelType = stFrameInfo.enPixelType; break;
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR8:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG8:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB8:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG8:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR10:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG10:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB10:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG10:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR12:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG12:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB12:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG12:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR10_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG10_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB10_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG10_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGR12_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerRG12_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerGB12_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_BayerBG12_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_YUV422_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_YUV422_YUYV_Packed:
                case MyCamera.MvGvspPixelType.PixelType_Gvsp_YCBCR411_8_CBYYCRYY:
                    enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed; break;
            }
            IntPtr pImage = Marshal.UnsafeAddrOfPinnedArrayElement(buffArr, 0);
            MyCamera.MV_PIXEL_CONVERT_PARAM stConverPixelParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();
            stConverPixelParam.nWidth = stFrameInfo.nWidth;
            stConverPixelParam.nHeight = stFrameInfo.nHeight;
            stConverPixelParam.pSrcData = pData;
            stConverPixelParam.nSrcDataLen = stFrameInfo.nFrameLen;
            stConverPixelParam.enSrcPixelType = stFrameInfo.enPixelType;
            stConverPixelParam.enDstPixelType = enDstPixelType;
            stConverPixelParam.pDstBuffer = pImage;
            stConverPixelParam.nDstBufferSize = buffSize;
            rtn = cameraCurr[index].MV_CC_ConvertPixelType_NET(ref stConverPixelParam);
            if (rtn != MyCamera.MV_OK) return null;

            if (enDstPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8)
            {
                Bitmap _image = new Bitmap(stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nWidth * 1, PixelFormat.Format8bppIndexed, pImage);
                ColorPalette cp = _image.Palette;
                for (int i = 0; i < 256; i++)
                    cp.Entries[i] = Color.FromArgb(i, i, i);
                _image.Palette = cp;

                //int picSize = _image.Width * _image.Height;
                //byte[] _buffer = new byte[picSize];
                //Array.Copy(buffArr, _buffer, picSize);

                return _image;
            }
            else
            {
                for (int i = 0; i < stFrameInfo.nHeight; i++)
                {
                    for (int j = 0; j < stFrameInfo.nWidth; j++)
                    {
                        byte chRed = buffArr[i * stFrameInfo.nWidth * 3 + j * 3];
                        buffArr[i * stFrameInfo.nWidth * 3 + j * 3] = buffArr[i * stFrameInfo.nWidth * 3 + j * 3 + 2];
                        buffArr[i * stFrameInfo.nWidth * 3 + j * 3 + 2] = chRed;
                    }
                }
                Bitmap _image = new Bitmap(stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nWidth * 3, PixelFormat.Format24bppRgb, pImage);
                //int picSize = _image.Width * _image.Height * 3;
                //byte[] _buffer = new byte[picSize];
                //Array.Copy(buffArr, _buffer, picSize);
                return _image;
            }
        }
        public override HObject CaptureOnImage(string name)
        {
            int index = cameraName.FindIndex(s => s == name);
            if (index == -1)
            {
                _errInfo = name + "Not find";
                return null;
            }
            if (cameraCurr[index] != null)
            {
            }
            else
            {
                Open(name);
            } 

            try
            {
                int rtn = cameraCurr[index].MV_CC_StartGrabbing_NET();
                if (rtn != MyCamera.MV_OK)
                {
                    _errInfo = "Can not grab one : " + rtn;
                    return null;
                } 
                MyCamera.MV_FRAME_OUT FrameInfo = new MyCamera.MV_FRAME_OUT();
                int nRet = cameraCurr[index].MV_CC_GetImageBuffer_NET(ref FrameInfo, 1000);
                // ch:获取一帧图像 | en:Get one image
                if (MyCamera.MV_OK == nRet)
                {
                    Console.WriteLine("Get Image Buffer:" + "Width[" + Convert.ToString(FrameInfo.stFrameInfo.nWidth) + "] , Height[" + Convert.ToString(FrameInfo.stFrameInfo.nHeight)
                                    + "] , FrameNum[" + Convert.ToString(FrameInfo.stFrameInfo.nFrameNum) + "]");

                    HObject ho_Imagetemp;
                    HOperatorSet.GenImage1(out ho_Imagetemp, "byte", FrameInfo.stFrameInfo.nWidth, FrameInfo.stFrameInfo.nHeight, FrameInfo.pBufAddr);

                    if (FrameInfo.pBufAddr != IntPtr.Zero)
                    {
                        nRet = cameraCurr[index].MV_CC_FreeImageBuffer_NET(ref FrameInfo);
                        if (nRet != MyCamera.MV_OK)
                        {
                            Console.WriteLine("Free Image Buffer fail:{0:x8}", nRet);
                        }
                    }
                    return ho_Imagetemp;
                }
                else
                {
                    Console.WriteLine("No data:{0:x8}", nRet);
                } 
            }
            catch (Exception ex)
            {
                _errInfo = ex.Message;
                return null;
            }
            finally
            {
                cameraCurr[index].MV_CC_StopGrabbing_NET();
            }
            return null;
        }
    }

}