using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;


namespace FunctionalSubstructure
{
    
    /// <summary>
    /// Class representing a sequence of thumbnails in a flow layout panel.
    /// </summary>
    public class ThumbnailsSequence : FlowLayoutPanel
    {

        private delegate ThumbnailBox CreateThumbnailBoxDelegate(int i);
        
        /// <summary>
        /// The directory where images reside.
        /// </summary>
        private string currentDirectory;

        /// <summary>
        /// The list of image files within the directory.
        /// </summary>
        private List<ImageFile> imageFiles;

        private TasksDispatcher tasksDispatcher;

        /// <summary>
        /// The currently selected thumbnail.
        /// </summary>
        private ThumbnailBox currentThumbnail;

        /// <summary>
        /// Determines whether or not the navigation through the thumbnails should reset
        /// their border status when navigated to.
        /// </summary>
        private bool allowSetThumbnailBorder;

        private bool pendingAction;


        /// <summary>
        /// Constructor.
        /// </summary>
        public ThumbnailsSequence()
            : base()
        {
            this.DoubleBuffered = true;
            this.allowSetThumbnailBorder = true;
            this.pendingAction = false;

            this.VerticalScroll.SmallChange = 25;
            this.VerticalScroll.LargeChange = 50;

            this.imageFiles = new List<ImageFile>();

            this.MouseMove += new MouseEventHandler(ThumbnailsSequence_MouseMove);
        }


        public void SetPendingAction()
        {
            this.pendingAction = true;
        }


        private void ThumbnailsSequence_MouseMove(object sender, MouseEventArgs e)
        {
            if ((currentThumbnail != null) && (!currentThumbnail.Focused))
                currentThumbnail.Focus();
        }


        /// <summary>
        /// Adds the new thumbnails to the container control.
        /// </summary>
        private void AddNewThumbnails()
        {
            try
            {
                ImageFolder container = new ImageFolder(currentDirectory);
                imageFiles = container.ImagesList;
            }
            catch { }
        }


		/// <summary>
        /// Adds the specific thumbnails to the container control.
        /// </summary>
        private void AddNewThumbnails(List<Image> images)
        {
            try
            {
				this.imageFiles = new List<ImageFile>();
				int fileindex = 0;
				foreach (Image img in images)
				{
					this.imageFiles.Add(new ImageFile(img, fileindex++));
				}
            }
            catch { }
        }


        /// <summary>
        /// Removes the thumbnails from the container control.
        /// </summary>
        public void DisposeOfPreviousThumbnails()
        {
            this.currentThumbnail = null;

            foreach (ThumbnailBox thumbnail in this.Controls)
                thumbnail.Dispose();

            this.Controls.Clear();

            foreach (ImageFile anImageFile in imageFiles)
                anImageFile.Dispose();
        }


        /// <summary>
        /// Shows the thumbnails on the screen.
        /// </summary>
        public void ShowThumbnails()
        {
            this.SuspendLayout();
            
            this.DisposeOfPreviousThumbnails();
            this.AutoScrollPosition = new Point(0, 0);
            this.AddNewThumbnails();

            this.ResumeLayout(true);

            this.SetThumbnails();
        }

		/// <summary>
        /// Shows the thumbnails on the screen.
        /// </summary>
        public void ShowThumbnails(List<Image> images)
        {
            this.SuspendLayout();
            
            this.DisposeOfPreviousThumbnails();
            this.AutoScrollPosition = new Point(0, 0);
            this.AddNewThumbnails(images);

            this.ResumeLayout(true);

            this.SetThumbnails2();
        }


        /// <summary>
        /// Sets the directory where images reside.
        /// </summary>
        public string CurrentDirectory
        {
            set
            { 
                this.currentDirectory = value;
            }
        }


        /// <summary>
        /// Gets or sets the currently selected thumbnail.
        /// </summary>
        public ThumbnailBox CurrentThumbnail
        {
            get { return currentThumbnail; }
            set { currentThumbnail = value; }
        }


        /// <summary>
        /// Sets the border of the currently selected thumbnail to a given border style.
        /// </summary>
        /// <param name="borderStyle">The border style to be applied to the current thumbnail</param>
        private void SetThumbnailBorder(BorderStyle borderStyle)
        {
            if (allowSetThumbnailBorder == true)
            {
                if (currentThumbnail != null)
                {
                    currentThumbnail.SetBorder(borderStyle);
                    currentThumbnail.Select();
                }
            }
        }


        /// <summary>
        /// Moves to the given thumbnail in the sequence.
        /// </summary>
        public void MoveToThumbnail(ThumbnailBox thumbnail)
        {
            if (thumbnail != null)
            {
                SetThumbnailBorder(BorderStyle.None);
                currentThumbnail = thumbnail;
                SetThumbnailBorder(BorderStyle.FixedSingle);
                ScrollControlIntoView(currentThumbnail);
            }
        }

		public void InvokeSuggestion()
		{
			Program.GetFormMain().RegisterObject(currentThumbnail.ThumbnailIndex);
		}

        /// <summary>
        /// Moves to the next thumbnail in the sequence, if any.
        /// </summary>
        public void MoveToNextThumbnail()
        {
            MoveToThumbnail(this.NextThumbnail);
        }

        /// <summary>
        /// Moves to the previous thumbnail in the sequence, if any.
        /// </summary>
        public void MoveToPreviousThumbnail()
        {
            MoveToThumbnail(this.PreviousThumbnail);
        }


        /// <summary>
        /// Moves to the upper thumbnail in the sequence, if any.
        /// </summary>
        public void MoveToUpperThumbnail()
        {
            MoveToThumbnail(this.UpperThumbnail);
        }

        /// <summary>
        /// Moves to the lower thumbnail in the sequence, if any.
        /// </summary>
        public void MoveToLowerThumbnail()
        {
            MoveToThumbnail(this.LowerThumbnail);
        }

        /// <summary>
        /// Moves to the left thumbnail in the sequence, if any.
        /// </summary>
        public void MoveToLeftThumbnail()
        {
            MoveToThumbnail(this.LeftThumbnail);
        }

        /// <summary>
        /// Moves to the right thumbnail in the sequence, if any.
        /// </summary>
        public void MoveToRightThumbnail()
        {
            MoveToThumbnail(this.RightThumbnail);
        }



        /// <summary>
        /// Gets the next thumbnail in the sequence.
        /// </summary>
        public ThumbnailBox NextThumbnail
        {
            get
            {
                if (currentThumbnail == null)
                {
                    if (this.Controls.Count > 0)
                        return (ThumbnailBox)this.Controls[0];
                    else
                        return null;
                }
                else
                {
                    if (currentThumbnail.ThumbnailIndex < this.Controls.Count - 1)
                        return (ThumbnailBox)this.Controls[currentThumbnail.ThumbnailIndex + 1];
                    else
                        return null;
                }
            }
        }

        /// <summary>
        /// Gets the previous thumbnail in the sequence.
        /// </summary>
        public ThumbnailBox PreviousThumbnail
        {
            get
            {
                if (currentThumbnail == null)
                {
                    if (this.Controls.Count > 0)
                        return (ThumbnailBox)this.Controls[this.Controls.Count - 1];
                    else
                        return null;
                }
                else
                {
                    if (currentThumbnail.ThumbnailIndex > 0)
                        return (ThumbnailBox)this.Controls[currentThumbnail.ThumbnailIndex - 1];
                    else
                        return null;
                }
            }
        }


        /// <summary>
        /// Gets the upper thumbnail in the visual representation of the sequence.
        /// </summary>
        public ThumbnailBox UpperThumbnail
        {
            get
            {
                if (currentThumbnail == null)
                {
                    if (this.Controls.Count > 0)
                        return (ThumbnailBox)this.Controls[0];
                    else
                        return null;
                }
                else
                {
                    allowSetThumbnailBorder = false;
                    
                    ThumbnailBox currentThumbnailCopy = currentThumbnail;
                    ThumbnailBox upperThumbnail = null;

                    MoveToPreviousThumbnail();
                    while ((this.PreviousThumbnail != null) &&
                           (currentThumbnailCopy.Location.X != currentThumbnail.Location.X))
                        MoveToPreviousThumbnail();

                    if ((currentThumbnailCopy.Location.X == currentThumbnail.Location.X) &&
                        (currentThumbnailCopy.Location.Y > currentThumbnail.Location.Y))
                        upperThumbnail = currentThumbnail;
                    MoveToThumbnail(currentThumbnailCopy);

                    allowSetThumbnailBorder = true;
                    return upperThumbnail;
                }
            }
        }

        /// <summary>
        /// Gets the lower thumbnail in the visual representation of the sequence.
        /// </summary>
        public ThumbnailBox LowerThumbnail
        {
            get
            {
                if (currentThumbnail == null)
                {
                    if (this.Controls.Count > 0)
                        return (ThumbnailBox)this.Controls[0];
                    else
                        return null;
                }
                else
                {
                    allowSetThumbnailBorder = false;
                    
                    ThumbnailBox currentThumbnailCopy = currentThumbnail;
                    ThumbnailBox lowerThumbnail = null;

                    MoveToNextThumbnail();
                    while ((this.NextThumbnail != null) &&
                           (currentThumbnailCopy.Location.X != currentThumbnail.Location.X))
                        MoveToNextThumbnail();

                    if ((currentThumbnailCopy.Location.X == currentThumbnail.Location.X) &&
                        (currentThumbnailCopy.Location.Y < currentThumbnail.Location.Y))
                        lowerThumbnail = currentThumbnail;
                    MoveToThumbnail(currentThumbnailCopy);

                    allowSetThumbnailBorder = true;
                    return lowerThumbnail;
                }
            }
        }

        /// <summary>
        /// Gets the left thumbnail in the visual representation of the sequence.
        /// </summary>
        public ThumbnailBox LeftThumbnail
        {
            get
            {
                if (currentThumbnail == null)
                {
                    if (this.Controls.Count > 0)
                        return (ThumbnailBox)this.Controls[0];
                    else
                        return null;
                }
                else
                {
                    ThumbnailBox leftThumbnail = this.PreviousThumbnail;
                    if ((leftThumbnail != null) && (leftThumbnail.Location.Y != currentThumbnail.Location.Y))
                        leftThumbnail = null;

                    return leftThumbnail;
                }
            }
        }

        /// <summary>
        /// Gets the right thumbnail in the visual representation of the sequence.
        /// </summary>
        public ThumbnailBox RightThumbnail
        {
            get
            {
                if (currentThumbnail == null)
                {
                    if (this.Controls.Count > 0)
                        return (ThumbnailBox)this.Controls[0];
                    else
                        return null;
                }
                else
                {
                    ThumbnailBox rightThumbnail = this.NextThumbnail;
                    if ((rightThumbnail != null) && (rightThumbnail.Location.Y != currentThumbnail.Location.Y))
                        rightThumbnail = null;

                    return rightThumbnail;
                }
            }
        }

		/// <summary>
		/// read from program
		/// </summary>
		private void SetThumbnails2()
        {
            tasksDispatcher = new TasksDispatcher(GenerateThumbnail2, SetThumbnailImage, imageFiles.Count);
            tasksDispatcher.Start();
        }


        private void GenerateThumbnail2(object index)
        {
            ThumbnailBox tb;
            
            if (this.InvokeRequired)
                tb = (ThumbnailBox)this.Invoke(new CreateThumbnailBoxDelegate(GenerateThumbnailHelper), (int)index);
            else
                tb = GenerateThumbnailHelper((int)index);
        }

		/// <summary>
		/// read from disc
		/// </summary>
        private void SetThumbnails()
        {
            tasksDispatcher = new TasksDispatcher(GenerateThumbnail, SetThumbnailImage, imageFiles.Count);
            tasksDispatcher.Start();
        }


        private void GenerateThumbnail(object index)
        {
            ThumbnailBox tb;
            
            if (this.InvokeRequired)
                tb = (ThumbnailBox)this.Invoke(new CreateThumbnailBoxDelegate(GenerateThumbnailHelper), (int)index);
            else
                tb = GenerateThumbnailHelper((int)index);

            tb.ReadImageFromDiscThread();
        }

        private ThumbnailBox GenerateThumbnailHelper(int i)
        {
            ThumbnailBox tb = new ThumbnailBox(this, i, imageFiles[i]);
            this.Controls.Add(tb);

            if (currentThumbnail == null)
                MoveToThumbnail(tb);

            return tb;
        }

        private void SetThumbnailImage(object index)
        {
            ThumbnailBox aThumbnailBox = (ThumbnailBox)this.Controls[(int)index];
            aThumbnailBox.SetThumbnailImageThread();
        }


        public void StopThumbnailsGeneration()
        {
            if (tasksDispatcher != null)
                tasksDispatcher.Stop();
        }


        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            if ((pendingAction) && (currentThumbnail != null))
            {
                ScrollControlIntoView(currentThumbnail);
                pendingAction = false;
            }
        }

    }

}
