using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using System.Timers;

using Lumenera.USB;
using LumeneraCamera;

namespace LumeneraCamera
{
    public partial class ImageDisplay : UserControl
    {
        LucamClass cam;
        private Bitmap myImage;                         // Buffer for the Bitmap Image.
        private byte[] pdata;                           // Raw Image Buffer.
        byte[] rgbImage;                                // RGB Image buffer.
        //private double zoomFactor = 1;                  // Zoom Factor buffer.
        DateTime imageDateTime;
        dll.LucamFrameFormat ff;                        // Frame format of acquisition.
        private bool imageSave = false;
        private string blackFrames;

        public string BlackFrameList
        {
            get
            {
                return blackFrames;
            }
        }
        
        public ImageDisplay(Object camera)
        {
            InitializeComponent();
            cam = new LucamClass();
            cam = (LucamClass) camera;
            imageSave = false;

        }
      public DateTime ImageTiming
        {
            get
            {
                return (imageDateTime);
            }
        }

        public bool ImageBlackTest(IntPtr camera)
        {
            int imageSize =0;
            dll.LucamFrameFormat ff = new dll.LucamFrameFormat();
            ff= api.GetFormat(camera);
           
            //Image size calculation.
            imageSize = (ff.Width/ff.SubSampleX) * (ff.Height / ff.SubSampleY);
            if (ff.PixelFormat == dll.LucamPixelFormat.PF_16)
                imageSize *=2;          // Double image size if in 16 bits mode;

            // Memory allocation
            pdata = new byte[imageSize];

            // Image Caption.
            if (!dll.LucamTakeVideo(camera,1,pdata)) return(false);

            int intensity = 0, counter = 0;
            for (int y = 0; y < ff.Height/ff.SubSampleY ; y++)
            {
                for (int x = 0; x < ff.Width/ff.SubSampleX ; x++)
                {
                    intensity += pdata[(y * (ff.Width/ff.SubSampleX)) + x];
                    counter++;
                }
            }
            if ((int)(intensity / counter)< 10)
                return (false);


            return (true);
        }

        public int ImageTimedBlackTest(IntPtr camera, int nbImage, ref float frameRate)
        {
            int imageSize = 0;
            int FrameErrorCounter = 0;
            dll.LucamFrameFormat ff = new dll.LucamFrameFormat();
            ff = api.GetFormat(camera);
            DateTime start= new DateTime();
            DateTime stop = new DateTime();
            TimeSpan timeTravel = new TimeSpan();
            TimeSpan timeAction = new TimeSpan();
            start = DateTime.Now;
            stop = DateTime.Now;
            timeAction = stop - start;
            
            float fr = api.GetFrameRate(camera);
            //Image size calculation.
            imageSize = (ff.Width / ff.SubSampleX) * (ff.Height / ff.SubSampleY);
            if (ff.PixelFormat == dll.LucamPixelFormat.PF_16)
                imageSize *= 2;          // Double image size if in 16 bits mode;

            // Memory allocation
            pdata = new byte[imageSize*nbImage];

            // Image Caption.
            start = DateTime.Now;
            if (!dll.LucamTakeVideo(camera, nbImage, pdata)) return (nbImage);
            stop = DateTime.Now;
            timeTravel = stop - start;
            frameRate = (float) (nbImage / (timeTravel.TotalSeconds-timeAction.TotalSeconds));
            
            int intensity = 0, counter = 0;
            blackFrames = ""; //reset string,
            for (int i=0; i<nbImage; i++)
            {
                intensity = 0;
                counter = 0;
                for (int y = 0; y < ff.Height / ff.SubSampleY; y++)
                {
                    for (int x = 0; x < ff.Width / ff.SubSampleX; x++)
                    {
                        intensity += pdata[(imageSize *i)+(y * (ff.Width / ff.SubSampleX)) + x];
                        counter++;
                    }
                }
                if ((int)(intensity / counter) < 10)
                {
                    FrameErrorCounter++;
                    blackFrames += string.Format("{0}, ", i);
                }
            }

            return (FrameErrorCounter);
        }

        public int ImageTimedBlackTest(IntPtr  camera, int nbImage, ref float frameRate, ref dll.LucamSnapshot snap)
        {
            int imageSize = 0;
            int FrameErrorCounter = 0;
            DateTime start = new DateTime();
            DateTime stop = new DateTime();
            TimeSpan timeTravel = new TimeSpan();
            TimeSpan timeAction = new TimeSpan();
            start = DateTime.Now;
            stop = DateTime.Now;
            timeAction = stop - start;
           
            //Image size calculation.
            imageSize = (snap.Format.Width  / snap.Format.SubSampleX ) * (snap.Format.Height  / snap.Format.SubSampleY );
            if (ff.PixelFormat == dll.LucamPixelFormat.PF_16)
                imageSize *= 2;          // Double image size if in 16 bits mode;

            // Memory allocation
            byte[][] rawData = new byte[nbImage][];
            for (int i=0; i<nbImage;i++)
            {
            rawData[i] = new byte[imageSize];
            }

            // Image Caption.
            dll.LucamEnableFastFrames(camera, ref snap);
            start = DateTime.Now;
            for (int i = 0; i < nbImage; i++)
            {
                if (!dll.LucamTakeFastFrame(camera, rawData[i]))
                {
                    dll.LucamDisableFastFrames(camera);
                    return (i);
                }
            }
            stop = DateTime.Now;
            timeTravel = stop - start;
            dll.LucamDisableFastFrames(camera);
            
            frameRate = (float)(nbImage / (timeTravel.TotalSeconds - timeAction.TotalSeconds));

            int intensity = 0, counter = 0;
            blackFrames = ""; //reset string,
            for (int i = 0; i < nbImage; i++)
            {
                intensity = 0;
                counter = 0;
                for (int y = 0; y < snap.Format.Height  / snap.Format.SubSampleY ; y++)
                {
                    for (int x = 0; x < snap.Format.Width  / snap.Format.SubSampleX ; x++)
                    {
                        intensity += rawData[i][(y * (snap.Format.Width  / snap.Format.SubSampleX)) + x];
                        counter++;
                    }
                }
                if ((int)(intensity / counter) < 10)
                {
                    FrameErrorCounter++;
                    blackFrames += string.Format("{0}, ", i);
                }
            }

            return (FrameErrorCounter);
        }
         
        public bool ImageTest(ref dll.LucamSnapshot snap)
        {
            int imageSize = 0;
            if (!api.IsCameraValid(cam.CHandle)) return (false);

            // Image size calculation.
            imageSize = (snap.Format.Width * snap.Format.Height);
            if (snap.Format.PixelFormat == dll.LucamPixelFormat.PF_16)
                imageSize *= 2;                  // Double image size if in 16 bits mode;

            //Memory allocation.
            pdata = new byte[imageSize];

            // Image Caption.
            if (!dll.LucamTakeSnapshot(cam.CHandle, ref snap, pdata)) return (false);
            imageDateTime = DateTime.Now;
            int intensity=0, counter=0;
            for (int y = 0; y < snap.Format.Height; y++)
            {
                for (int x = 0; x < snap.Format.Width; x++)
                {
                    intensity += pdata[(y * snap.Format.Width) + x];
                    counter++;
                }
            }
            if ((int)(intensity / counter) == 0)
                return (false);


            return (true);
        }

        public bool ImageCapture(ref dll.LucamConversion conversion)
        {
            int imageSize = 0;
            int rgbImageSize = 0;
            BitmapData myImageData;
            Rectangle lockdata;
            ff = new dll.LucamFrameFormat();
            if (!api.IsCameraValid(cam.CHandle)) return (false);
//            if (!cam.IsStreamingVideo) return (false);  
            ff = api.GetFormat(cam.CHandle);

            // Image size calculation.
            imageSize = (ff.Width / ff.SubSampleX) * (ff.Height / ff.SubSampleY);
            if (ff.PixelFormat == dll.LucamPixelFormat.PF_16)
                imageSize *= 2;                  // Double image size if in 16 bits mode;
            rgbImageSize = 0;
            rgbImageSize = imageSize * 3;

            //Memory allocation.
            pdata = new byte[imageSize];
            rgbImage = new byte[rgbImageSize];

            // Image Caption.
            if (!dll.LucamTakeVideo(cam.CHandle, 1, pdata)) return (false);
            imageDateTime = DateTime.Now;

            //RGB Converstion
                if (ff.PixelFormat == dll.LucamPixelFormat.PF_8)
                {
                    if (!dll.LucamConvertFrameToRgb24(cam.CHandle, rgbImage, pdata, ff.Width / ff.SubSampleX, ff.Height / ff.SubSampleY, dll.LucamPixelFormat.PF_8, ref conversion)) return (false);
                }
                else
                {
                    if (!dll.LucamConvertFrameToRgb48(cam.CHandle, rgbImage, pdata, ff.Width / ff.SubSampleX, ff.Height / ff.SubSampleY, dll.LucamPixelFormat.PF_16, ref conversion)) return (false);
                }

                // Create bitmap with RGB
                if (ff.PixelFormat == dll.LucamPixelFormat.PF_8)
                    myImage = new Bitmap(ff.Width / ff.SubSampleX, ff.Height / ff.SubSampleY, PixelFormat.Format24bppRgb );
                else
                    myImage = new Bitmap(ff.Width / ff.SubSampleX, ff.Height / ff.SubSampleY, PixelFormat.Format48bppRgb);
                myImageData = new BitmapData();
                lockdata = new Rectangle(0, 0, ff.Width / ff.SubSampleX, ff.Height / ff.SubSampleY);
                myImageData = myImage.LockBits(lockdata, ImageLockMode.ReadWrite, myImage.PixelFormat, myImageData);
                System.Runtime.InteropServices.Marshal.Copy(rgbImage, 0, myImageData.Scan0, rgbImageSize);
                myImage.UnlockBits(myImageData);
                myImage.RotateFlip(RotateFlipType.RotateNoneFlipY);

                //setup panel.
                //imagePanel.Width= myImage.Width;
                //imagePanel.Height = myImage.Height;
                imagePanel.Image = myImage;
                
            return (true);
            }

        public bool ImageSnapshot(ref dll.LucamSnapshot snap, ref dll.LucamConversion  conversion)
        {
            int imageSize = 0;
            int rgbImageSize = 0;
            BitmapData myImageData;
            Rectangle lockdata;
            if (!api.IsCameraValid(cam.CHandle)) return (false);

            // Image size calculation.
            imageSize = (snap.Format.Width  / snap.Format.SubSampleX ) * (snap.Format.Height / snap.Format.SubSampleY );
            if (snap.Format.PixelFormat == dll.LucamPixelFormat.PF_16)
                imageSize *= 2;                  // Double image size if in 16 bits mode;
            rgbImageSize = 0;
            rgbImageSize = imageSize * 3;

            //Memory allocation.
            pdata = new byte[imageSize];
            rgbImage = new byte[rgbImageSize];

            // Image Caption.
            if (!dll.LucamTakeSnapshot(cam.CHandle, ref snap, pdata)) return (false);
            imageDateTime = DateTime.Now;

            //RGB Converstion
            if (snap.Format.PixelFormat == dll.LucamPixelFormat.PF_8)
            {
                if (!dll.LucamConvertFrameToRgb24(cam.CHandle, rgbImage, pdata, snap.Format.Width / snap.Format.SubSampleX, snap.Format.Height / snap.Format.SubSampleY, dll.LucamPixelFormat.PF_8, ref conversion)) return (false);
            }
            else
            {
                if (!dll.LucamConvertFrameToRgb48(cam.CHandle, rgbImage, pdata, snap.Format.Width / snap.Format.SubSampleX, snap.Format.Height / snap.Format.SubSampleY, dll.LucamPixelFormat.PF_16, ref conversion)) return (false);
            }

            // Create bitmap with RGB
            if (snap.Format.PixelFormat  == dll.LucamPixelFormat.PF_8)
                myImage = new Bitmap(snap.Format.Width / snap.Format.SubSampleX, snap.Format.Height / snap.Format.SubSampleY, PixelFormat.Format24bppRgb);
            else
                myImage = new Bitmap(snap.Format.Width / snap.Format.SubSampleX, snap.Format.Height / snap.Format.SubSampleY, PixelFormat.Format48bppRgb);
            myImageData = new BitmapData();
            lockdata = new Rectangle(0, 0, snap.Format.Width / snap.Format.SubSampleX, snap.Format.Height / snap.Format.SubSampleY);
            myImageData = myImage.LockBits(lockdata, ImageLockMode.ReadWrite, myImage.PixelFormat, myImageData);
            System.Runtime.InteropServices.Marshal.Copy(rgbImage, 0, myImageData.Scan0, rgbImageSize);
            myImage.UnlockBits(myImageData);
            myImage.RotateFlip(RotateFlipType.RotateNoneFlipY);

            //setup panel.
            //imagePanel.Width= myImage.Width;
            //imagePanel.Height = myImage.Height;
            imagePanel.Image = myImage;

            return (true);
        }

        public void SaveImage()
        {
            saveImageToFile(this, null);
        }
        public void ImageClose()
        {
            if (!imageSave)
                SaveImage();
        }

        private void saveImageToFile(object sender, EventArgs e)
        {
            SaveFileDialog fileDlg = new SaveFileDialog();                          // Create file dialog box.
            fileDlg.InitialDirectory = "My Documents\\My Pictures";                 // Setup initial directory where to save fils.
            fileDlg.SupportMultiDottedExtensions = true;                            // Make sure to support multi dotted extension.
            //fileDlg.FileName = this.Text;
            //fileDlg.FileName.Replace('/', '-');
            //fileDlg.FileName.Replace(':', '-');
            fileDlg.DefaultExt = ".bmp";                                            // Set default extension.
            fileDlg.AddExtension = true;                                            // Make sure to add the extension if not in filename.
            // Default type of files.
            fileDlg.Filter = "BMP Files(*.bmp)|*.bmp|JPEG Files(*.jpg;*.jpeg)|*.jpg;*jpeg|GIF Files(*.gif)|*.gif|TIFF Files(*.tiff)|*.tiff|PNG Files(*.png)|*.png | RAW File (*.raw)|*.raw";
            if (ff.PixelFormat == dll.LucamPixelFormat.PF_16)
            {
                fileDlg.Filter = "TIFF Files(*.tiff)|*.tiff|RAW File (*.raw)|*.raw";
                fileDlg.DefaultExt = ".raw";
            }
            // TODO : 4 make sure to save with our function to optimize it.
            if (ff.PixelFormat == dll.LucamPixelFormat.PF_8)
            {
                try
                {
                    if (fileDlg.ShowDialog() == DialogResult.OK)                        // Open file dialog box.
                    {
                        switch (fileDlg.FilterIndex)                                   // Check type of file to save to. 
                        {
                            case 1: // BMP
                                myImage.Save(fileDlg.FileName, ImageFormat.Bmp);        // Save BMP file.    
                                break;
                            case 2: // jpg
                                myImage.Save(fileDlg.FileName, ImageFormat.Jpeg);       // Save JPEG file.
                                break;
                            case 3: // Gif
                                myImage.Save(fileDlg.FileName, ImageFormat.Gif);        // Save GIG File.
                                break;
                            case 4: // Tiff
                                myImage.Save(fileDlg.FileName, ImageFormat.Tiff);       // Save TIFF file.
                                break;
                            case 5: // Png
                                myImage.Save(fileDlg.FileName, ImageFormat.Png);       // Save PNG file.
                                break;
                            case 6: // RAW    
                                string filename = fileDlg.FileName;                     // Prepare to save in binary mode.
                                if (!filename.Contains("."))                            // Check if the extention is present in the file name.
                                    filename = filename + "." + "raw";                  // Add extention when no present.
                                FileInfo f = new FileInfo(filename);                    // Setup file header to creater.
                                BinaryWriter wt = new BinaryWriter(f.OpenWrite());      // Open file in creation mode.
                                wt.Write(pdata);                                        // Write Image RAW date to file.
                                wt.Close();                                             // Close file.
                                break;
                        }
                        imageSave = true;                                               // Set file Saving flag.

                    }
                }
                catch
                {
                    MessageBox.Show("Cannot save" + this.Text);                         // Display error message if an error occur.
                }
            }
            else
            {
                try
                {
                    if (fileDlg.ShowDialog() == DialogResult.OK)                        // Open file dialog box.
                    {
                        switch (fileDlg.FilterIndex)                                   // Check type of file to save to. 
                        {
                            case 1: // Tiff
                                myImage.Save(fileDlg.FileName, ImageFormat.Tiff );        // Save BMP file.    
                                break;
                            case 2: // jpg
                                string filename = fileDlg.FileName;                     // Prepare to save in binary mode.
                                if (!filename.Contains("."))                            // Check if the extention is present in the file name.
                                    filename = filename + "." + "raw";                  // Add extention when no present.
                                FileInfo f = new FileInfo(filename);                    // Setup file header to creater.
                                BinaryWriter wt = new BinaryWriter(f.OpenWrite());      // Open file in creation mode.
                                wt.Write(pdata);                                        // Write Image RAW date to file.
                                wt.Close();                                             // Close file.
                                break;
                            
                        }
                        imageSave = true;                                               // Set file Saving flag.

                    }
                }
                catch
                {
                    MessageBox.Show("Cannot save" + this.Text);                         // Display error message if an error occur.
                }
            }

        }

        private void imageDisplay_FormClosed(object sender, FormClosedEventArgs e)
        {

            if (!imageSave)                             // Check if the file was already saved.
            {
                this.UseWaitCursor = true;              // Place the form cursor to wait cursor mode.
                saveImageToFile(this, e);                  // Save Image.
                this.UseWaitCursor = false;             // Return cursor to is default mode.
            }
        }

    }
}
