// Motion Detector
//
// Copyright © Andrew Kirillov, 2005
// andrew.kirillov@gmail.com
//

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;

namespace motion {
    /// <summary>
    /// Summary description for CameraWindow.
    /// </summary>
    public class CameraWindow : System.Windows.Forms.Control {
        private Camera camera = null;
        private bool autosize = false;
        private bool needSizeUpdate = false;
        private bool firstFrame = true;

        // AutoSize property
        [DefaultValue(false)]
        public override bool AutoSize {
            get { return autosize; }
            set {
                autosize = value;
                UpdatePosition();
            }
        }

        // Camera property
        [Browsable(false)]
        public Camera Camera {
            get { return camera; }
            set {
                // lock
                Monitor.Enter(this);
                // detach event
                if (camera != null) {
                    camera.NewFrame -= new EventHandler(camera_NewFrame);
                }

                camera = value;
                needSizeUpdate = true;
                firstFrame = true;

                // atach event
                if (camera != null) {
                    camera.NewFrame += new EventHandler(camera_NewFrame);
                }

                // unlock
                Monitor.Exit(this);
            }
        }

        // Constructor
        public CameraWindow() {
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true);
        }

        //private static int paintn;
        private string Painting = null;  // Bug check
        // Paint control
        protected override void OnPaint(PaintEventArgs pe) {
            if (this.DesignMode) {  // Try to fix resizing bug -- probably should remove this
                pe.Graphics.DrawString("Design Mode", this.Font, Brushes.White, 0, 0);
                return;
            }
            if ((needSizeUpdate) || (firstFrame)) {
                UpdatePosition();
                needSizeUpdate = false;
            }

            // lock
            //Monitor.Enter(this);

            if (Painting != null)
                Debugger.Break();
//             if (this.InvokeRequired)
//                 Debugger.Break();
//             if (Thread.CurrentThread.Name == null)
//                 Thread.CurrentThread.Name = "CameraWindow#" + Interlocked.Increment(ref paintn);
            Painting = string.Format("{0} {1}", Thread.CurrentThread.Name, Thread.CurrentThread.GetHashCode());
            try {
                Graphics g = pe.Graphics;
                Rectangle rc = this.ClientRectangle;
                using (Pen pen = new Pen(Color.Black, 1)) {

                    // draw rectangle
                    g.DrawRectangle(pen, rc.X, rc.Y, rc.Width - 1, rc.Height - 1);

                    if (camera != null) {
                        try {

                            // draw frame
                            if (camera.LastFrame != null) {
                                try {
                                    //camera.LockFrame("Paint");
                                    if (camera.LastFrame != null) { // To be safe since we did the last check outside the lock
                                        g.DrawImage(camera.LastFrame, rc.X + 1, rc.Y + 1, rc.Width - 2, rc.Height - 2);
                                        firstFrame = false;
                                    }
                                }
                                finally {
                                    //camera.UnlockFrame();
                                }
                            }
                            else {
                                // Create font and brush
                                using (var drawFont = new Font("Arial", 12))
                                using (var drawBrush = new SolidBrush(Color.White))
                                    g.DrawString("Connecting ...", drawFont, drawBrush, new PointF(5, 5));
                            }
                        }
                        catch (Exception ex) {
                            Debug.WriteLine(ex.Message);
                            Debugger.Break();
                        }

                    }

                    //pen.Dispose();
                }

                // unlock
                //Monitor.Exit(this);

                base.OnPaint(pe);
            }
            finally {
                Painting = null;
            }
        }

        // Update position and size of the control
        public void UpdatePosition() {
            if (this.DesignMode)
                return; // Don't screw around

            // lock
            //Monitor.Enter(this);
            lock (this) {
                if ((autosize) && (this.Parent != null)) {
                    Rectangle rc = this.Parent.ClientRectangle;
                    int width = 320;
                    int height = 240;

                    if (camera != null) {
                        camera.Lock("UpdatePosition");

                        // get frame dimension
                        if (camera.LastFrame != null) {
                            width = camera.LastFrame.Width;
                            height = camera.LastFrame.Height;
                        }
                        camera.Unlock();
                    }

                    //
                    this.SuspendLayout();
                    this.Location = new Point((rc.Width - width - 2) / 2, (rc.Height - height - 2) / 2);
                    this.Size = new Size(width + 2, height + 2);
                    this.ResumeLayout();

                }
                // unlock
                //Monitor.Exit(this);
            }
        }

        // On new frame ready
        private void camera_NewFrame(object sender, System.EventArgs e) {
            Invalidate();
        }

        [Browsable(false)]
        public Bitmap BitMap { get { return camera == null ? null : camera.LastFrame; } }

        public Color GetPixel(Point Pos) {  // Get pixel as per mouse position
            try {
                if (this.BitMap == null)
                    return Color.Empty;
                float px = (float)Pos.X / this.Width;
                float py = (float)Pos.Y / this.Height;
                var bm = this.BitMap;
                try {
                    return bm.GetPixel((int)(bm.Width * px), (int)(bm.Height * py));
                }
                catch {
                }
            }
            catch {
            }
            return Color.Empty;
        }
    }
}
