using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Drawing.Design;

using videosource;


namespace motion {
    public partial class MainForm : Form {
        public MainForm() {
            InitializeComponent();
            this.Size = new Size(707, 604); // Work around bug till we figure it out
        }
        public static MainForm mForm { get; private set; }
        //        public static PaintForm PF { get; private set; }
        public string SuffixInitials { get { return txtInitials.Text == "" ? "" : "_" + txtInitials.Text; } }
        public string SuffixIntensity { get { return txtIntensity.Text == "" ? "" : "_" + txtIntensity.Text; } }
        public string SuffixHemi { get { return txtHemi.Text == "" ? "" : "_" + txtHemi.Text; } }
        private const int statLength = 15;
        private int statIndex = 0, statReady = 0;
        private int[] statCount = new int[statLength];

        private MotionDetector1 detector = new MotionDetector1();
        private bool croppingEnabled = true;
        

        //Public variables
        public int threshold = 220;
        public Rectangle videoCrop = new Rectangle();
        public int videoCropX { get { return videoCrop.X; } set { videoCrop = new Rectangle(value, videoCropY, videoCropWidth, videoCropHeight); } }
        public int videoCropY { get { return videoCrop.Y; } set { videoCrop = new Rectangle(videoCropX, value, videoCropWidth, videoCropHeight); } }
        public int videoCropWidth { get { return videoCrop.Width; } set { videoCrop = new Rectangle(videoCropX, videoCropY, value, videoCropHeight); } }
        public int videoCropHeight { get { return videoCrop.Height; } set { videoCrop = new Rectangle(videoCropX, videoCropY, videoCropWidth, value); } }
        //public int videoCropX = 0;
        //public int videoCropY = 0;
        //public int videoCropWidth = -1;
        //public int videoCropHeight = -1;
        public bool controlMouse = false;
        public bool enableClick = false;
        public bool invertCursorMovements = false;
        public int resizeFactor = 3;
        public float x1 = 0, y1 = 0;
        public float x2 = 0, y2 = 0;
        public bool leftMouseButtonDown = false;
        public bool timeOutPaint = false;
        public int colorNum;
        public bool ifVisField = false;
        public bool openEyes = false;
        public bool clearText = false;

        // On form closing
        private void MainForm_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
            CloseFile();
        }

        // Close the main form
        private void exitFileItem_Click(object sender, System.EventArgs e) {
            this.Close();
        }

        // On "Help->About"
        private void aboutHelpItem_Click(object sender, System.EventArgs e) {
            AboutForm form = new AboutForm();
            form.ShowDialog();
        }

        // Open file
        private void openFileItem_Click(object sender, System.EventArgs e) {
            //open xml to load.
            if (openFileDialog1.InitialDirectory == "")
                openFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
            if (openFileDialog1.ShowDialog() == DialogResult.OK) {
                var PF = new PaintForm() {

                    Text = openFileDialog1.FileName,

                };
                PF.Loader(openFileDialog1.FileName);
                PF.WindowState = FormWindowState.Maximized;

                PF.Visible = true;

            }

            //if (ofd.ShowDialog.ShowDialog() == DialogResult.OK) {

            //// create video source
            //VideoFileSource fileSource = new VideoFileSource();
            //fileSource.VideoSource = ofd.FileName;

            //// open it
            //OpenVideoSource(fileSource);

            //// enable camera window
            //cameraWindow.Enabled = true;
            // }
        }


        // Open URL
        private void openURLFileItem_Click(object sender, System.EventArgs e) {
            URLForm form = new URLForm();

            form.Description = "Enter URL of an updating JPEG from a web camera:";
            form.URLs = new string[]
				{
                    //"http://aleksandriacamk1.it.helsinki.fi/axis-cgi/jpg/image.cgi?resolution=320x240",
                    //"http://stareat.it.helsinki.fi/axis-cgi/jpg/image.cgi?resolution=320x240",
                    //"http://194.18.89.220/axis-cgi/jpg/image.cgi?resolution=320x240",
                    //"http://212.247.228.34/axis-cgi/jpg/image.cgi?resolution=352x240"
				};

            if (form.ShowDialog(this) == DialogResult.OK) {
                // create video source
                JPEGSource jpegSource = new JPEGSource();
                jpegSource.VideoSource = form.URL;
                jpegSource.Password = form.Password;
                jpegSource.Login = form.Name;
                jpegSource.PreAuthenticate = form.PreAuthenticate;

                // open it
                OpenVideoSource(jpegSource);

                // enable camera window
                cameraWindow.Enabled = true;
            }
        }

        // Open MJPEG URL
        private void openMJEPGFileItem_Click(object sender, System.EventArgs e) {
            URLForm form = new URLForm();

            form.Description = "Enter URL of an MJPEG video stream:";
            form.URLs = new string[]
				{
                    //"http://hanselman.dyndns.org:81/mjpeg.cgi",
                    //"http://sun.jerseyinsight.com/trafficbeaumont/nph-update.cgi",
                    //"http://peeper.axisinc.com/nph-manupdate.cgi",
                    //"http://marc15ter.vac.hu/nphMotionJpeg?Resolution=320x240&Quality=Standard",
                    //"http://213.200.232.69:8080/axis-cgi/mjpg/video.cgi?resolution=320x240"
				};

            if (form.ShowDialog(this) == DialogResult.OK) {
                // create video source
                MJPEGSource mjpegSource = new MJPEGSource();
                mjpegSource.VideoSource = form.URL;
                mjpegSource.Login = form.Login;
                mjpegSource.Password = form.Password;
                mjpegSource.PreAuthenticate = form.PreAuthenticate;
                mjpegSource.AuthWithHomePage = form.AuthWithHomePage;

                // open it
                OpenVideoSource(mjpegSource);

                // enable camera window
                cameraWindow.Enabled = true;
            }
        }

        // Open MMS
        private void openMMSFileItem_Click(object sender, System.EventArgs e) {
            MMSForm form = new MMSForm();

            if (form.ShowDialog(this) == DialogResult.OK) {
                // create video source
                VideoStream mmsSource = new VideoStream();
                mmsSource.VideoSource = form.URL;

                // open it
                OpenVideoSource(mmsSource);

                // enable camera window
                cameraWindow.Enabled = true;
            }
        }

        // Open local capture device
        private void openLocalFileItem_Click(object sender, System.EventArgs e) {
            CaptureDeviceForm form = new CaptureDeviceForm();

            if (form.ShowDialog(this) == DialogResult.OK) {
                // create video source
                CaptureDevice localSource = new CaptureDevice();
                localSource.VideoSource = form.Device;

                // open it
                OpenVideoSource(localSource);

                // enable camera window
                cameraWindow.Enabled = true;
            }
        }

        // Open video source
        private void OpenVideoSource(IVideoSource source) {
            // set busy cursor
            this.Cursor = Cursors.WaitCursor;

            // close previous file
            CloseFile();

            // create camera
            Camera camera = new Camera(source, detector);
            // start camera
            camera.Start();

            // attach camera to camera window
            cameraWindow.Camera = camera;

            // reset statistics
            statIndex = statReady = 0;

            // start timer
            timer.Start();

            this.Cursor = Cursors.Default;
        }

        // Close current file
        private void CloseFile() {
            Camera camera = cameraWindow.Camera;

            if (camera != null) {
                // detach camera from camera window
                cameraWindow.Camera = null;

                // signal camera to stop
                camera.SignalToStop();
                // wait for the camera
                camera.WaitForStop();

                camera = null;

                if (detector != null)
                    detector.Reset();
            }
        }

        // On timer event - gather statistic
        private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
            Camera camera = cameraWindow.Camera;

            if (camera != null) {
                // get number of frames for the last second
                statCount[statIndex] = camera.FramesReceived;

                // increment indexes
                if (++statIndex >= statLength)
                    statIndex = 0;
                if (statReady < statLength)
                    statReady++;

                float fps = 0;

                // calculate average value
                for (int i = 0; i < statReady; i++) {
                    fps += statCount[i];
                }
                fps /= statReady;

                statCount[statIndex] = 0;

                fpsPanel.Text = fps.ToString("F2") + " fps " + rgb;
            }
        }

        // Update motion detector
        private void SetMotionDetector() {
            Camera camera = cameraWindow.Camera;

            if (camera != null) {
                try {
                    camera.Lock("SetMotionDetector");
                    camera.MotionDetector = detector;

                    // reset statistics
                    statIndex = statReady = 0;
                }
                finally {
                    camera.Unlock();
                }
            }
        }

        private void thresholdTrackBar_Scroll(object sender, EventArgs e) {
            // Update value on the label
            thresholdLabel.Text = "Current threshold: " + thresholdTrackBar.Value.ToString();
            threshold = thresholdTrackBar.Value;
        }

        private void MainForm_Load(object sender, EventArgs e) {
            //detector.mForm = this;
            MainForm.mForm = this;   // It's static
        }

        private void controlCursorCheckBox_CheckedChanged(object sender, EventArgs e) {
            //Control cursor
            controlMouse = controlCursorCheckBox.Checked;
            enableClickCheckBox.Enabled = controlCursorCheckBox.Checked;
            invertCursorCheckBox.Enabled = controlCursorCheckBox.Checked;
        }

        private void enableClickCheckBox_CheckedChanged(object sender, EventArgs e) {
            //Enable/Disable clicking with laser
            enableClick = enableClickCheckBox.Checked;
        }

        private void invertCursorCheckBox_CheckedChanged(object sender, EventArgs e) {
            //Invert cursor movements
            invertCursorMovements = invertCursorCheckBox.Checked;
        }

        private void resizeFactorUpDown_ValueChanged(object sender, EventArgs e) {
            //Set resize factor
            resizeFactor = (int)resizeFactorUpDown.Value;
        }

        string rgb = "";
        private Color LastRGB;
        private void cameraWindow_MouseClick(object sender, MouseEventArgs e) {
            try {
                var Pos = new Point(e.X, e.Y);
                // BUG BUG BUG -- doesn't check flags correctly
                if ((e.Button & MouseButtons.Right) != 0) {
                    //Reset video cropping
                    croppingEnabled = true;
                    videoCrop = new Rectangle();
                    //videoCropX = 0;
                    //videoCropY = 0;
                    //videoCropWidth = -1;
                    //videoCropHeight = -1;
                }
                if ((e.Button & MouseButtons.Left) != 0) {
                    // Get the pixel value
                    var cam = sender as CameraWindow;
                    if (cam != null) {
                        var pix = cam.GetPixel(Pos);
                        LastRGB = pix;
                        if (pix.IsEmpty)
                            rgb = "Empty ";
                        else {
                            rgb = string.Format("R:{0}, G:{1}, B:{2} ", pix.R, pix.G, pix.B);
                            if (!MotionDetector1.DistanceFrom.IsEmpty)
                                rgb += string.Format("Distance={0} ", Utility.PixelData.ColourDistance(MotionDetector1.DistanceFrom, pix));
                        }
                    }
                    rgb += "@" + Pos.ToString();
                }
            }
            catch (Exception ex) {
                Debug.WriteLine("MouseClick " + ex.Message);
            }
        }

        private void cameraWindow_MouseMove(object sender, MouseEventArgs e) {
            if ((e.Button & MouseButtons.Left) != 0) {
                if (croppingEnabled) {
                    //Compute location of x2 and y2 into camera coordinates
                    x2 = e.X * ((float)videoCropWidth / cameraWindow.Width);
                    y2 = e.Y * ((float)videoCropHeight / cameraWindow.Height);

                    //Set internal flag to know the user is dragging with the left mouse button down
                    leftMouseButtonDown = true;
                }
            }
        }

        private void cameraWindow_MouseDown(object sender, MouseEventArgs e) {
            if ((e.Button & MouseButtons.Left) != 0) {
                if (croppingEnabled) {
                    //Compute location of x1 and y1 into camera coordinates
                    x1 = e.X * ((float)videoCropWidth / cameraWindow.Width);
                    y1 = e.Y * ((float)videoCropHeight / cameraWindow.Height);
                    //this.Capture = true;
                }
            }
        }

        private void cameraWindow_MouseUp(object sender, MouseEventArgs e) {
            //if (this.Capture && (e.Button & MouseButtons.Left) != 0) {
            //    this.Capture = false;
            //}
            if (leftMouseButtonDown) {
                EndCapture();   // Old method
            }
        }

        private void EndCapture() {
            if (!croppingEnabled)
                return;
            //Set internal flag to know the user is not dragging
            //with the left mouse button down anymore
            leftMouseButtonDown = false;

            //Disable video cropping
            croppingEnabled = false;

            //Calculate width and height of selected region
            int width = Math.Abs((int)x2 - (int)x1);
            int height = Math.Abs((int)y2 - (int)y1);

            if ((width == 0) || (height == 0)) {
                //Cancel cropping
                croppingEnabled = true;
                return;
            }

            //Determine videoCropX and videoCropY

            if (x2 < x1)
                x1 = x2;

            if (y2 < y1)
                y1 = y2;

            videoCropX = (int)x1;
            videoCropY = (int)y1;

            //Check if the region selected by the user is within bounds
            if (videoCropX < 0)
                videoCropX = 0;
            else if ((videoCropX + width) > videoCropWidth)
                width -= width - (videoCropWidth - videoCropX);

            if (videoCropY < 0)
                videoCropY = 0;
            else if ((videoCropY + height) > videoCropHeight)
                height -= height - (videoCropHeight - videoCropY);

            //Set video cropping width and height
            videoCropWidth = width;
            videoCropHeight = height;
        }

        private void clearMotionToolStripMenuItem_Click(object sender, EventArgs e) {
            if (detector != null)
                detector.Clear();
        }

        private void menuItem2_Click(object sender, EventArgs e) {
            try {
                colorDialog1.Color = MotionDetector1.DistanceFrom;
                if (!LastRGB.IsEmpty && MotionDetector1.DistanceFrom.IsEmpty)
                    colorDialog1.Color = LastRGB;
                var result = colorDialog1.ShowDialog();
                clrPanel.Visible = result == DialogResult.OK;
                if (result == DialogResult.OK) {
                    MotionDetector1.DistanceFrom = colorDialog1.Color;
                    lblCT2.BackColor = colorDialog1.Color;
                }
                else
                    MotionDetector1.DistanceFrom = Color.Empty;
            }
            catch (Exception ex) {
                Debug.WriteLine(ex.Message);
            }
        }

        public int ColorThreshold = 50000;
        //private void trkCT_Validated(object sender, EventArgs e) {
        //    ColorThreshold = (sender as TrackBar).Value;
        //    lblCT.Text = "Color Threshold: " + ColorThreshold;
        //}

        private void trkCT_ValueChanged(object sender, EventArgs e) {
            ColorThreshold = (sender as TrackBar).Value;
            lblCT.Text = "Color Threshold: " + ColorThreshold;
        }


        public enum PaintWhatEnum { none, brightPaint, colorPaint, VisField };
        public static PaintWhatEnum PaintWhat = PaintWhatEnum.none;
        internal static PaintForm PForm { get; set; }
        private void StartPaint(string title, PaintWhatEnum PaintWhat) {
            if (PForm == null)
                PForm = new PaintForm() {
                    WindowState = FormWindowState.Maximized,
                    BackColor = Color.Black,
                    Visible = true
                };
            MainForm.PaintWhat = PaintWhat;
            PForm.Text = title;
            PForm.FormClosed += new FormClosedEventHandler(delegate {
                PForm = null;
                MainForm.PaintWhat = PaintWhatEnum.none;
            });
            PForm.UpdateColorEvent += new PaintForm.dlgUpdateColorHandler(PForm_UpdateColorEvent);
        }

        void PForm_UpdateColorEvent(PaintForm sender, string CName) {
            this.Invoke(new MethodInvoker(delegate { Colorlbl.Text = CName; }));
        }

        void dele(PaintForm sender, string CName) {
            throw new NotImplementedException();
        }
        //private void ckPaint_CheckedChanged(object sender, EventArgs e) {
        //    var cb = sender as CheckBox;
        //    if (!cb.Checked)
        //        return;
        //    StartPaint("Color Paint");
        //}

        //private void ckBrightPaint_CheckedChanged(object sender, EventArgs e) {
        //    var cb = sender as CheckBox;
        //    if (!cb.Checked)
        //        return;
        //    StartPaint("Bright Paint");
        //}

        //private void ckVisField_CheckedChanged(object sender, EventArgs e) {
        //    var cb = sender as CheckBox;
        //    if (!cb.Checked)
        //        return;
        //    StartPaint("Visual Field");
        //}

        private void ColorPaintbtn_Click(object sender, EventArgs e) {
            var cb = sender as CheckBox;
            StartPaint("Color Paint Button", PaintWhatEnum.colorPaint);
        }

        private void brightPaintbtn_Click(object sender, EventArgs e) { //Initialize a new Bright Pos paint form. 
            var cb = sender as Button;
            StartPaint("Bright Paint Button", PaintWhatEnum.brightPaint);
        }

        private void VisFieldbtn_Click(object sender, EventArgs e) {
            ifVisField = true;
            var cb = sender as CheckBox;
            StartPaint("Visual Field", PaintWhatEnum.VisField);
        }

        private void chTimeOutPaint_CheckedChanged(object sender, EventArgs e) {
            timeOutPaint = (sender as CheckBox).Checked;
        }

        private void txtIntensity_Validated(object sender, EventArgs e) {
            if (!txtIntensity.Text.Contains("%")) {
                txtIntensity.Text = txtIntensity.Text + "%";
            }
        }

        private void btnColorNum_Click(object sender, EventArgs e) {
            //PForm.colorNum = 0;
            if (PForm != null)
                PForm.ResetColor();
        }

        //private void Colorlbl_Click(object sender, EventArgs e) {
        //    //Colorlbl.Text = PForm.ColoredPens[colorNum++ % ColoredPens.Length];

        //}

        private void Saverbtn_Click(object sender, EventArgs e) { //Save Painted Path to XML
            if (PForm != null)
                PForm.Saver();
        }

        private void clearPathbtn_Click(object sender, EventArgs e) {
            if (PForm != null)
                PForm.ClearPath(false);

            PForm.ClearMyPath();
            if (clearText) {
                txtInitials.Text = "";
                txtIntensity.Text = "";
                txtHemi.Text = "";
            }
            clearText = false;

        }

        private void ckEyesOpen_CheckedChanged(object sender, EventArgs e) {
            openEyes = (sender as CheckBox).Checked;
        }

    }
}