using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;

namespace ICubeSDKSample
{
  
    public partial class Form1 : Form
    {
        public delegate int MyCallback(IntPtr pBuf, int lBufferSize, int pCBContext);

        MyCallback cb;  // If the callback is called asynchronously, you have to ensure that the
                        // callback delegate is alive as long as the function pointer is needed.

        int g_iCurrentCam = 0;
        int g_iCurrentFormat = 0;
        int[] g_ModIndexCam = new int[10];
        int g_TriggerMode = ICube.TRIG_SW_START;
        static bool bSaveRaw = false;
        static bool bTimerEnabled = false;

        // Parameter control (just 3 exemplary parameter)
        public const int NUM_OF_PARAM = 3;
        int g_iCurrentParam;
        int[] nParamNum = new int[NUM_OF_PARAM]{ICube.REG_BRIGHTNESS,ICube.REG_CONTRAST,ICube.REG_EXPOSURE_TIME };
        string[] nParamName = new string[NUM_OF_PARAM] {"REG_BRIGHTNESS","REG_CONTRAST","REG_EXPOSURE_TIME" };

        public Form1()
        {
            InitializeComponent();
            StringBuilder sApiVersion = new StringBuilder(ICube.NETCAM_VERSION_LENGTH);
            try
            {
                ICube.ICubeSDK_GetVersion(ICube.API_VERSION, sApiVersion);
                labelApiVersion.Text = sApiVersion.ToString();
                // Initialize parameter controls
                for (int i = 0; i < NUM_OF_PARAM; i++)
                    comboBoxParameters.Items.Add(nParamName[i]);
                
                comboBoxParameters.SelectedIndex = 0;
                g_iCurrentParam = nParamNum[comboBoxParameters.SelectedIndex];
                comboBoxParameters.Enabled = false;
                bTimerEnabled = true; 
            }
            catch
            {
                MessageBox.Show("Error: No ICubeSDK.dll available");
                Environment.Exit(0);    // exit application
            }
        }

        //---------------------------------------------------------------------
        // callback which is used for grabbing raw or RGB24 data from camera.
        //
        static int MyCallbackFunc(IntPtr pBuf , int lBufferSize , int pCBContext)
        {
            if (bSaveRaw)
            {
                bSaveRaw = false;

                byte[] buf = new byte[lBufferSize];
                // copy from unmanaged to managed memory
                Marshal.Copy(pBuf, buf, 0, lBufferSize);
                // write to file
                FileStream fs = new FileStream("test.raw", FileMode.Create);
                fs.Write(buf, 0, lBufferSize);
                fs.Close();                
            }
            return 42;
        }

        //---------------------------------------------------------------------
        //
        // ICubeSDK_SetMode() sets the basis format (e.g. 640x480)
        // ICubeSDK_SetBinSkip() sets Binning/Skipping on the basis format.
        // If ICubeSDK_SetBinSkip->nParameter==0, ICubeSDK_SetBinSkip has
        // no effect.
        // ICubeSDK_SetResolution sets the Region of interest.
        // If roi_prop.bEnabled==0,ICubeSDK_SetResolution has
        // no effect.  
        // It is not possible to set bin/skip and Roi.
        // 
        private void StartCam()
        {     
             cb = new MyCallback(MyCallbackFunc);
             IntPtr cbPtr = Marshal.GetFunctionPointerForDelegate(cb);

             // necessary, if Callback-Flag(ICubeSDK_Start)==true 
            if (ICube.ICubeSDK_SetCallback(g_iCurrentCam, ICube.CALLBACK_RAW, cbPtr, 0) != ICube.IC_SUCCESS)
                MessageBox.Show("Error: Set callback");
            
            // optional to set format, different from highest format
            if (ICube.ICubeSDK_SetMode(g_iCurrentCam, g_iCurrentFormat) != ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_SetMode");

            // optional to set bin skip mode
            int g_iBinSkipParam = ICube.BIN_SKIP_OFF;
            int g_iBinSkipMode = ICube.MODE_SKIP;

            if (ICube.ICubeSDK_SetBinSkip(g_iCurrentCam, g_iBinSkipParam,g_iBinSkipMode)!= ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_SetBinSkip");

            // optional to set region of interest mode
             ICube.ROI_PROPERTY roi_prop = new ICube.ROI_PROPERTY();
             roi_prop.bEnabled = ICube.OFF;   // set to ON to enable roi mode
             roi_prop.nXPos = 0;
             roi_prop.nYPos = 0;
             roi_prop.nXRes = 640;
             roi_prop.nYRes = 480;

            if (ICube.ICubeSDK_SetResolution(g_iCurrentCam,ref roi_prop) != ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_SetResolution");

            if (ICube.ICubeSDK_Start(g_iCurrentCam, IntPtr.Zero, 1, 1) != ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_Start");

        }

        //---------------------------------------------------------------------
        private void CloseCam()
        {
            if (ICube.ICubeSDK_IsOpen(g_iCurrentCam) == ICube.IS_OPEN)
            {
                if (ICube.ICubeSDK_Close(g_iCurrentCam) != ICube.IC_SUCCESS)
                    MessageBox.Show("Error: ICubeSDK_Close");
            }
        }
        private void buttonInit_Click(object sender, EventArgs e)
        {
            StringBuilder sCamName = new StringBuilder(ICube.NETCAM_NAME_LENGTH);
            int stat = 0;
            int numDevices = ICube.ICubeSDK_Init();
            if (numDevices < 1)
            {
                MessageBox.Show("No devices");
                return;
            }
            String s;
            comboBoxCam.Items.Clear();
            for (int i = 0; i < numDevices; i++)
            {
                stat = ICube.ICubeSDK_GetName(i, sCamName);
                if(stat != ICube.IC_SUCCESS)
                {
                    if (stat == ICube.IC_DRIVER_VERSION)
                        MessageBox.Show("Error: driver version mismatch");
                    else
                        MessageBox.Show("Error getting model name");
                    return;
                }
                s = String.Format("({0}) {1}", i+1, sCamName);
                comboBoxCam.Items.Add(s);  
            }
            comboBoxCam.SelectedIndex = 0;
            g_iCurrentCam=0;
        }

        private void buttonOpen_Click(object sender, EventArgs e)
        {
            int nlist = 10;

            if (ICube.ICubeSDK_Open(g_iCurrentCam) != ICube.IC_SUCCESS)
            {
                MessageBox.Show("Error: ICubeSDK_Open");
                return;
            }           
            // get all formats
            if (ICube.ICubeSDK_GetModeList(g_iCurrentCam, ref nlist, g_ModIndexCam)!= ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_GetModeList");

            comboBoxFormat.Items.Clear();
            for (int i = 0; i < nlist; i++)
                comboBoxFormat.Items.Add(GetModString(g_ModIndexCam[i]));            

            // get current format
            if (ICube.ICubeSDK_GetMode(g_iCurrentCam, ref g_iCurrentFormat) != ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_GetMode");

            for (int i = 0; i < nlist; i++)
            {
                if(g_ModIndexCam[i] == g_iCurrentFormat)
                    comboBoxFormat.SelectedIndex = i;
            }

            InitParameterControl(g_iCurrentParam);

            uint nVal = 0;  // get color processing value
            if (ICube.ICubeSDK_GetCamParameter(g_iCurrentCam, ICube.REG_COLOR_PROCESSING, ref nVal) != ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_GetCamParameter");
            checkBoxColorProcessing.Checked = Convert.ToBoolean(nVal); 

            comboBoxCam.Enabled = false;
            comboBoxParameters.Enabled = true;
        }

        // helper function
        private string GetModString(int nFormat) 
        {
            switch (nFormat){
                case ICube.MODE_320x240:
                    return "320x240";
                case ICube.MODE_640x480:
                    return "640x480";
                case ICube.MODE_752x480:
                    return "752x480";
                case ICube.MODE_800x600:
                    return "800x600";
                case ICube.MODE_1024x768:
                    return "1024x768";
                case ICube.MODE_1280x1024:
                    return "1280x1024";
                case ICube.MODE_1600x1200:
                    return "1600x1200";
                case ICube.MODE_2048x1536:
                    return "2048x1536";
                case ICube.MODE_2592x1944:
                    return "2592x1944";
                case ICube.MODE_3840x2748:
                    return "3840x2748";
                case ICube.MODE_1920x1200:
                    return "1920x1200";
                default:
                    return "0x0";
            }            
        }
        private void buttonStart_Click(object sender, EventArgs e)
        {
            StartCam();
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            if (ICube.ICubeSDK_Stop(g_iCurrentCam) != ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_Stop");
        }
        
        private void buttonClose_Click(object sender, EventArgs e)
        {
            CloseCam();
            comboBoxCam.Enabled = true;
            comboBoxParameters.Enabled = false;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            CloseCam();
        }
        private void comboBoxFormat_SelectedIndexChanged(object sender, EventArgs e)
        {
            g_iCurrentFormat = g_ModIndexCam[comboBoxFormat.SelectedIndex];
        }

        private void comboBoxCam_SelectedIndexChanged(object sender, EventArgs e)
        {
            g_iCurrentCam = comboBoxCam.SelectedIndex;
        }
        //---------------------------------------------------------------------
        // Timer
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (bTimerEnabled)
            {
                if (ICube.ICubeSDK_IsStarted(g_iCurrentCam) == ICube.IS_STARTED)
                {
                    int nBadFrames = 0;
                    int nGoodFrames = 0;
                    String s;

                    if (ICube.ICubeSDK_GetBrokenFrames(g_iCurrentCam, ref nBadFrames) != ICube.IC_SUCCESS)
                        MessageBox.Show("Error: ICubeSDK_GetBrokenFrames");
                    if (ICube.ICubeSDK_GetGoodFrames(g_iCurrentCam, ref nGoodFrames) != ICube.IC_SUCCESS)
                        MessageBox.Show("Error: ICubeSDK_GetGoodFrames");

                    s = String.Format("bad frames: {0} ", nBadFrames);
                    toolStripStatusLabelBadFrames.Text = s;
                    s = String.Format("frames: {0} ", nGoodFrames);
                    toolStripStatusLabelGoodFrames.Text = s;
                }
            }
        }
        //---------------------------------------------------------------------
        // Save controls
        private void buttonSaveBMP_Click(object sender, EventArgs e)
        {
            if (ICube.ICubeSDK_SaveToFile(g_iCurrentCam,"ICubeTest.bmp") != ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_SaveToFile");
        }

        private void buttonSaveAVI_Click(object sender, EventArgs e)
        {
            if (ICube.ICubeSDK_SaveAvi(g_iCurrentCam, "ICubeTest.avi",ICube.AVI_DIB, 1) != ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_SaveAvi");
        }

        private void buttonSaveRaw_Click(object sender, EventArgs e)
        {
            bSaveRaw = true;    // save callback data to a raw-File
        }
        //---------------------------------------------------------------------
        // Flip controls
        private void checkBoxFlipH_CheckedChanged(object sender, EventArgs e)
        {
            uint  nFlipMode;
            if (checkBoxFlipH.Checked)
                nFlipMode = ICube.ON;
            else
                nFlipMode = ICube.OFF;

            if (ICube.ICubeSDK_SetCamParameter(g_iCurrentCam, ICube.REG_FLIPPED_H, nFlipMode) != ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_SetCamParameter");
        }

        private void checkBoxFlipV_CheckedChanged(object sender, EventArgs e)
        {
            uint nFlipMode;
            if (checkBoxFlipV.Checked)
                nFlipMode = ICube.ON;
            else
                nFlipMode = ICube.OFF;

            if (ICube.ICubeSDK_SetCamParameter(g_iCurrentCam, ICube.REG_FLIPPED_V, nFlipMode) != ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_SetCamParameter");
        }
        //---------------------------------------------------------------------
        // Trigger controls
        private void checkBoxEnableTrigger_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxEnableTrigger.Checked)
            {
                if (ICube.ICubeSDK_SetTrigger(g_iCurrentCam, g_TriggerMode) != ICube.IC_SUCCESS)
                    MessageBox.Show("Error: ICubeSDK_SetTrigger");
            }
            else
            {
                if (ICube.ICubeSDK_SetTrigger(g_iCurrentCam, ICube.TRIG_STOP) != ICube.IC_SUCCESS)
                    MessageBox.Show("Error: ICubeSDK_SetTrigger");
            }
            
        }

        private void radioButtonSWTrigger_CheckedChanged(object sender, EventArgs e)
        {
            g_TriggerMode = ICube.TRIG_SW_START;
        }

        private void radioButtonHWTrigger_CheckedChanged(object sender, EventArgs e)
        {
            g_TriggerMode = ICube.TRIG_HW_START;
        }

        private void buttonDoSWTrigger_Click(object sender, EventArgs e)
        {
            if (g_TriggerMode == ICube.TRIG_HW_START)
            {
                MessageBox.Show("Wrong Trigger mode!");
                return;
            }
            if (checkBoxEnableTrigger.Checked)
            {
                if (ICube.ICubeSDK_SetTrigger(g_iCurrentCam, ICube.TRIG_SW_DO) != ICube.IC_SUCCESS)
                    MessageBox.Show("Error: ICubeSDK_SetTrigger");
            }
            else
            {
                MessageBox.Show("Enable Trigger mode first!");
            }
        }
        //---------------------------------------------------------------------
        // Parameter controls
        private void comboBoxParameters_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (ICube.ICubeSDK_IsOpen(g_iCurrentCam) == ICube.IS_OPEN)
            {
                g_iCurrentParam = nParamNum[comboBoxParameters.SelectedIndex];
                // Initialize the selected parameter
                InitParameterControl(g_iCurrentParam);
            }
        }

        private void buttonSet_Click(object sender, EventArgs e)
        {
            uint nVal = (uint)trackBarParameter.Value;
            int nStat = ICube.ICubeSDK_SetCamParameter(g_iCurrentCam, g_iCurrentParam, nVal);
            if (nStat != ICube.IC_SUCCESS)
            {
                if (nStat == ICube.IC_IF_NOT_ENABLED)
                    // Brightness,Contrast,Hue,Saturation are belonging to the ColorProcessing module
                    // If REG_COLOR_PROCESSING is not enabled, this error will be thrown
                    MessageBox.Show("Error: Parameter not enabled!");
                else if (nStat == ICube.IC_COLOR_CAM_ONLY)
                    MessageBox.Show("Error: Parameter only for color models!");
                else
                    MessageBox.Show("Error: Set Parameter!");
            }            
        }
        private void InitParameterControl(int nType)
        {
            uint nVal=0;
            ICube.PARAM_PROPERTY param_prop = new ICube.PARAM_PROPERTY();

            if (ICube.ICubeSDK_GetCamParameterRange(g_iCurrentCam,nType,ref param_prop) != ICube.IC_SUCCESS)
            {
                MessageBox.Show("Error: ICubeSDK_GetCamParameterRange");
                return;
            }
            if (ICube.ICubeSDK_GetCamParameter(g_iCurrentCam, nType, ref nVal) != ICube.IC_SUCCESS)
            {
                MessageBox.Show("Error: ICubeSDK_GetCamParameter");
                return;
            }
            labelMin.Text = Convert.ToString(param_prop.nMin);
            labelMax.Text = Convert.ToString(param_prop.nMax);
            trackBarParameter.SetRange((int)param_prop.nMin, (int)param_prop.nMax);
            textBoxParameter.Text = Convert.ToString(nVal);
            trackBarParameter.Value = (int)nVal;

	        if(param_prop.bEnabled==1)				// Control is supported
	        {
                checkBoxAuto.Enabled = Convert.ToBoolean(param_prop.bAuto); 

		        if(param_prop.bAuto==1)			// Control supports auto-mode
		        {
    		        int bAuto=0;
                    if (ICube.ICubeSDK_GetParamAuto(g_iCurrentCam, nType,ref bAuto) != ICube.IC_SUCCESS)
                    {
                        MessageBox.Show("Error: ICubeSDK_GetParamAuto");
                        return;
                    }
                    checkBoxAuto.Checked = Convert.ToBoolean(bAuto);                	   
		        }

	            if(param_prop.bOnePush==1)			// Control supports one push-mode
	            {
                    // not implemented in this sample
                }
            }
    }

        private void trackBarParameter_Scroll(object sender, EventArgs e)
        {
            textBoxParameter.Text = Convert.ToString(trackBarParameter.Value);
        }

        private void checkBoxAuto_CheckedChanged(object sender, EventArgs e)
        {
            // if Auto exposure is ON, changing exposure is not allowed
            // (1044CU/BU) changing gain  values is not allowed !
            int nVal;
            if (checkBoxAuto.Checked)
                nVal=ICube.ON;
            else
                nVal = ICube.OFF;

            if (ICube.ICubeSDK_SetParamAuto(g_iCurrentCam, g_iCurrentParam, nVal) != ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_SetParamAuto");

        }

        private void checkBoxColorProcessing_CheckedChanged(object sender, EventArgs e)
        {
            // Brightness,Contrast,Hue,Saturation are belonging to the ColorProcessing module
            // they can be en/disabled through REG_COLOR_PROCCESSING
            // if non of these controls are used, disable to save CPU load
            uint nVal;
            if (checkBoxColorProcessing.Checked)
                nVal = ICube.ON;
            else
                nVal = ICube.OFF;
            if (ICube.ICubeSDK_SetCamParameter(g_iCurrentCam, ICube.REG_COLOR_PROCESSING, nVal) != ICube.IC_SUCCESS)
                MessageBox.Show("Error: ICubeSDK_SetCamParameter");
        }

        private void buttonToFile_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.Filter = "INI Files|*.ini";
            saveFileDialog1.Title = "Select a INI File";

            if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                int stat = ICube.ICubeSDK_CamParameterSet(g_iCurrentCam, ICube.PARAMETER_LOAD_TO_FILE, saveFileDialog1.FileName);
                if (stat != ICube.IC_SUCCESS)
                    MessageBox.Show("Error: ICubeSDK_SetCamParameter : " + stat.ToString());
            }  
        }

        private void buttonFromFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            openFileDialog1.Filter = "INI Files|*.ini";
            openFileDialog1.Title = "Select a INI File";

            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                int stat = ICube.ICubeSDK_CamParameterSet(g_iCurrentCam, ICube.PARAMETER_LOAD_FROM_FILE, openFileDialog1.FileName);
                if (stat != ICube.IC_SUCCESS)
                    MessageBox.Show("Error: ICubeSDK_SetCamParameter : " + stat.ToString());
            }  
        }   
    }
}