using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace AsyncCSharp
{
    public partial class MainWindow : Form
    {
        private CyberCs.ScanDataCallback m_fullImage;
        private CyberCs.ErrorReportCallback m_errorReport;

        public MainWindow()
        {
            InitializeComponent();
            m_fullImage = ScanData;
            m_errorReport = ErrorMessage;
        }

        private void MainWindow_Load(object sender, EventArgs e)
        {
            var ret = CyberCs.ScInit(m_fullImage, m_errorReport);
            if (ret == 0)
            {
                //This is normaly cause by the scanner not being connected.
                MessageBox.Show("Unable to init scanner");
                return;
            }

            paperStatusTm.Enabled = true; 

        }


        private void StartScnBtn_Click(object sender, EventArgs e)
        {
            CyberCs.ScSCalibrate(ConfigSettings.CV_CAL_STOPSCAN, 0);

            CyberCs.ScSCalibrate(ConfigSettings.CV_CAL_SET_RESO, (int)Resolutions.EACRmFULL2);
            //CyberCs.ScSCalibrate(ConfigSettings.CV_CAL_SET_RESO, (int)Resolutions.FullColour); // Use this to scan in colour.

            CyberCs.ScSCalibrate(ConfigSettings.CV_CAL_SET_DEV, (int)DeviceCode.EDEV200A4_1728);
            CyberCs.ScSCalibrate(ConfigSettings.CV_CAL_SET_LIGHT, 160); //set light 184
            CyberCs.ScSCalibrate(ConfigSettings.CV_CAL_STARTSCAN, 0);

            // Start scanning as soon as paper is detected.
            // This will reset back to off after every scan.
            CyberCs.ScSCalibrate(ConfigSettings.CV_CAL_FORCESCAN, 0); 

        }

        private void paperStatusTm_Tick(object sender, EventArgs e)
        {
            var paper = CyberCs.ScSCalibrate(ConfigSettings.CV_CAL_PAPER, 0);
            if(paper != 0)
            {
                paperLbl.Text = "Paper Detected";
            }
            else
            {
                paperLbl.Text = "No Paper";
            }

        }

        private void ReceiveImage(Bitmap image)
        {
            scanedImage.Image = image;
        }

        private void ReceiveError(int error, int type, string msg)
        {
            if(msg != null)
            {
                statusLbl.Text = String.Format("Debug Msg: {0}", msg);
            }
            else
            {
                statusLbl.Text = String.Format("Error type:{0} data:{1}", type, error);
            }
        }



        // These methods are the callback functions used by CyberSc to return scans and errors.
        // They are not called in the message loop thread and so can't touch any of the UI elements 
        // until they're invoked back onto the right thread.

        private void ScanData(ref CyberImg img)
        {

            var bitmap = new Bitmap(img.wWid, img.wHei, img.wWidBy, PixelFormat.Format1bppIndexed, img.pIm);
            
            // If this is a colour scan use this to create the bitmap.
            //var bitmap = new Bitmap(img.wWid, img.wHei, img.wWidBy, PixelFormat.Format24bppRgb, img.pIm);


            //The img.pIm isn't valid after this functions returns so make a copy of the data.
            var safeCopy = new Bitmap(bitmap);

            safeCopy.RotateFlip(RotateFlipType.RotateNoneFlipY); //The img.pIm data is mirrored.

            Action toThread = () => ReceiveImage(safeCopy);
            Invoke(toThread);
        }

    
        private void ErrorMessage(int error, int type)
        {
            // If this is a debg message type is really a char*
	        // Get a copy of the memory before this function returns.
            string msg = null;
            if((ErrorCodes)error == ErrorCodes.CV_DEBUG)
            {
                msg = Marshal.PtrToStringAnsi(new IntPtr(type));

            }

            Action toThread = () => ReceiveError(error, type, msg);
            Invoke(toThread);
        }

    }
}
