using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace DevComponents.DotNetBar
{
    /// 
    /// Represents class used to display toast notifications. A toast notification is a message that appears on the surface of the screen for a moment, 
    /// but it does not take focus (or pause the current activity), so it cannot accept any user input.
    /// Notification pops up on the surface of the specified Form or Control.
    /// It only fills the amount of space required for the message and the user's current activity remains visible and interactive.
    /// The notification automatically fades in and out after specified time interval.
    /// Notification text supports text-markup.
    /// 
    public static class ToastNotification
    {
        /// 
        /// Closes all toast notifications open on specified parent control.
        /// 
        /// Parent control.
        public static void Close(Control parent)
        {
            if (parent == null) throw new NullReferenceException("parent parameter for toast notification must be set.");
            Close(parent, IntPtr.Zero);
        }
        /// 
        /// Closes specified toast notification on parent control.
        /// 
        /// Parent control.
        /// Toast ID as returned by the Show method.
        public static void Close(Control parent, IntPtr toastId)
        {
            if (parent == null) throw new NullReferenceException("parent parameter for toast notification must be set.");
            if (toastId == IntPtr.Zero)
            {
                foreach (Control item in parent.Controls)
                {
                    if (item is ToastDisplay)
                        item.Visible = false;
                }
            }
            else
            {
                foreach (Control item in parent.Controls)
                {
                    if (item.Handle == toastId)
                    {
                        item.Visible = false;
                        break;
                    }
                }
            }
        }
        /// 
        /// Updates the already displayed toast text. Note that toast notification will not be resized.
        /// 
        /// Parent control which was used to show toast.
        /// Toast ID returned by the Show toast method.
        /// New toast notification text.
        public static void UpdateToast(Control parent, IntPtr toastId, string text)
        {
            if (toastId == IntPtr.Zero)
                throw new ArgumentException("toastId must be non zero value.");
            if(parent == null)
                throw new ArgumentException("parent Control must be specified.");
            foreach (Control item in parent.Controls)
            {
                if (item.Handle == toastId)
                {
                    ToastDisplay toast = (ToastDisplay)item;
                    toast.Text = text;
                    Size toastSize = toast.DesiredSize(_ToastMargin, parent.ClientRectangle);
                    if (toast.ToastPosition != null)
                        toast.Bounds = CalculateToastBounds(toast.ToastPosition.Value, parent.ClientRectangle, toastSize);
                    else
                        toast.Bounds = new Rectangle(toast.Bounds.X, toast.Bounds.Y, toastSize.Width, toastSize.Height);
                    break;
                }
            }
        }
        private static IntPtr ShowInternal(Control parent, string message, Image image, int timeoutInterval, eToastGlowColor toastGlowColor, eToastPosition? toastPosition, int x, int y)
        {
            if (parent == null) throw new NullReferenceException("parent parameter for toast notification must be set.");
            if (timeoutInterval < 1) timeoutInterval = 0;
            ToastDisplay toast = new ToastDisplay();
            toast.BackColor = Color.Transparent;
            toast.ToastBackColor = _ToastBackColor;
            toast.ForeColor = _ToastForeColor;
            if (_ToastFont != null) toast.Font = _ToastFont;
            bool isTerminalSession = NativeFunctions.IsTerminalSession();
            toast.Alpha = isTerminalSession ? 255 : 0;
            toast.Text = message;
            toast.Image = image;
            toast.GlowColor = toastGlowColor;
            toast.ToastPosition = toastPosition;
            parent.Controls.Add(toast);
            Size toastSize = toast.DesiredSize(_ToastMargin, parent.ClientRectangle);
            toast.BringToFront();
            if (toastPosition != null)
                toast.Bounds = CalculateToastBounds(toastPosition.Value, parent.ClientRectangle, toastSize);
            else
                toast.Bounds = new Rectangle(x, y, toastSize.Width, toastSize.Height);
            toast.Visible = true;
            IntPtr toastId = toast.Handle;
            if (!isTerminalSession)
            {
                Animation.AnimationInt anim = new DevComponents.DotNetBar.Animation.AnimationInt(new Animation.AnimationRequest(toast, "Alpha", 0, 255),
                        Animation.AnimationEasing.EaseOutQuad, 250);
                //anim.FixedStepCount = 10;
                anim.AutoDispose = true;
                anim.Start();
            }
            if (timeoutInterval > 0)
                BarUtilities.InvokeDelayed(new MethodInvoker(delegate { CloseToast(toast); }), timeoutInterval);
            return toastId;
        }
        /// 
        /// Displays the toast notification on top of the specified parent control, we recommend always using a parent form.
        /// 
        /// Parent form to display toast notification on top of
        /// Message to display.
        /// Image to display next to toast text.
        /// Interval in milliseconds after which the notification is hidden.
        /// Specifies toast-glow color used.
        /// Specifies the position of the toast notification.
        public static IntPtr Show(Control parent, string message, Image image, int timeoutInterval, eToastGlowColor toastGlowColor, eToastPosition toastPosition)
        {
            return ShowInternal(parent, message, image, timeoutInterval, toastGlowColor, toastPosition, 0, 0);
        }
        /// 
        /// Displays the toast notification on top of the specified parent control, we recommend always using a parent form.
        /// 
        /// Parent form to display toast notification on top of
        /// Message to display.
        /// Image to display next to toast text.
        /// Interval in milliseconds after which the notification is hidden.
        /// Specifies toast-glow color used.
        /// Specifies the X position of the toast notification with its parent window.
        /// Specifies the Y position of the toast notification with its parent window.
        public static IntPtr Show(Control parent, string message, Image image, int timeoutInterval, eToastGlowColor toastGlowColor, int x, int y)
        {
            return ShowInternal(parent, message, image, timeoutInterval, toastGlowColor, null, x, y);
        }
        private static Rectangle CalculateToastBounds(eToastPosition toastPosition, Rectangle parentClientRectangle, Size toastSize)
        {
            Rectangle displayBounds = Rectangle.Empty;
            if (toastPosition == eToastPosition.BottomCenter)
                displayBounds = new Rectangle(parentClientRectangle.X + (parentClientRectangle.Width - toastSize.Width) / 2,
                    parentClientRectangle.Bottom - toastSize.Height - _ToastMargin.Bottom,
                    toastSize.Width, toastSize.Height);
            else if (toastPosition == eToastPosition.BottomLeft)
                displayBounds = new Rectangle(parentClientRectangle.X + _ToastMargin.Left,
                    parentClientRectangle.Bottom - toastSize.Height - _ToastMargin.Bottom,
                    toastSize.Width, toastSize.Height);
            else if (toastPosition == eToastPosition.BottomRight)
                displayBounds = new Rectangle(parentClientRectangle.Right - _ToastMargin.Right - toastSize.Width,
                    parentClientRectangle.Bottom - toastSize.Height - _ToastMargin.Bottom,
                    toastSize.Width, toastSize.Height);
            else if (toastPosition == eToastPosition.MiddleCenter)
                displayBounds = new Rectangle(parentClientRectangle.X + (parentClientRectangle.Width - toastSize.Width) / 2,
                    parentClientRectangle.Y + (parentClientRectangle.Height - toastSize.Height) / 2,
                    toastSize.Width, toastSize.Height);
            else if (toastPosition == eToastPosition.MiddleLeft)
                displayBounds = new Rectangle(parentClientRectangle.X + _ToastMargin.Left,
                    parentClientRectangle.Y + (parentClientRectangle.Height - toastSize.Height) / 2,
                    toastSize.Width, toastSize.Height);
            else if (toastPosition == eToastPosition.MiddleRight)
                displayBounds = new Rectangle(parentClientRectangle.Right - _ToastMargin.Right - toastSize.Width,
                    parentClientRectangle.Y + (parentClientRectangle.Height - toastSize.Height) / 2,
                    toastSize.Width, toastSize.Height);
            else if (toastPosition == eToastPosition.TopCenter)
                displayBounds = new Rectangle(parentClientRectangle.X + (parentClientRectangle.Width - toastSize.Width) / 2,
                    parentClientRectangle.Y + _ToastMargin.Top,
                    toastSize.Width, toastSize.Height);
            else if (toastPosition == eToastPosition.TopLeft)
                displayBounds = new Rectangle(parentClientRectangle.X + _ToastMargin.Left,
                    parentClientRectangle.Y + _ToastMargin.Top,
                    toastSize.Width, toastSize.Height);
            else if (toastPosition == eToastPosition.TopRight)
                displayBounds = new Rectangle(parentClientRectangle.Right - _ToastMargin.Right - toastSize.Width,
                    parentClientRectangle.Y + _ToastMargin.Top,
                    toastSize.Width, toastSize.Height);
            return displayBounds;
        }
        /// 
        /// Displays the toast notification on top of the specified parent control, we recommend always using a parent form.
        /// 
        /// Parent form to display toast notification on top of
        /// Message to display.
        /// Image to display next to toast text.
        /// Interval in milliseconds after which the notification is hidden.
        /// /// Specifies toast-glow color used.
        public static IntPtr Show(Control parent, string message, Image image, int timeoutInterval, eToastGlowColor toastGlowColor)
        {
            return Show(parent, message, image, timeoutInterval, toastGlowColor, _DefaultToastPosition);
        }
        /// 
        /// Displays the toast notification on top of the specified parent control, we recommend always using a parent form, with default timeout interval.
        /// 
        /// Parent control to display toast notification on top of
        /// Message to display.
        public static IntPtr Show(Control parent, string message)
        {
            return Show(parent, message, null, _DefaultTimeoutInterval, _DefaultToastGlowColor);
        }
        /// 
        /// Displays the toast notification on top of the specified parent control, we recommend always using a parent form, with default timeout interval.
        /// 
        /// Parent control to display toast notification on top of
        /// Message to display.
        /// Specifies the position of the toast notification.
        public static IntPtr Show(Control parent, string message, eToastPosition toastPosition)
        {
            return Show(parent, message, null, _DefaultTimeoutInterval, _DefaultToastGlowColor, toastPosition);
        }
        /// 
        /// Displays the toast notification on top of the specified parent control, we recommend always using a parent form, with default timeout interval.
        /// 
        /// Parent control to display toast notification on top of
        /// Message to display.
        /// Image to display next to toast text.
        public static IntPtr Show(Control parent, string message, Image image)
        {
            return Show(parent, message, image, _DefaultTimeoutInterval, _DefaultToastGlowColor);
        }
        /// 
        /// Displays the toast notification on top of the specified parent control, we recommend always using a parent form.
        /// 
        /// Parent form to display toast notification on top of
        /// Message to display.
        /// Image to display next to toast text.
        /// Interval in milliseconds after which the notification is hidden.
        public static IntPtr Show(Control parent, string message, Image image, int timeoutInterval)
        {
            return Show(parent, message, image, timeoutInterval, _DefaultToastGlowColor);
        }
        /// 
        /// Displays the toast notification on top of the specified parent control, we recommend always using a parent form.
        /// 
        /// Parent form to display toast notification on top of
        /// Message to display.
        /// Interval in milliseconds after which the notification is hidden.
        public static IntPtr Show(Control parent, string message, int timeoutInterval)
        {
            return Show(parent, message, null, timeoutInterval, _DefaultToastGlowColor);
        }
        /// 
        /// Displays the toast notification on top of the specified parent control, we recommend always using a parent form.
        /// 
        /// Parent form to display toast notification on top of
        /// Message to display.
        /// Interval in milliseconds after which the notification is hidden.
        /// Specifies the position of the toast notification.
        public static IntPtr Show(Control parent, string message, int timeoutInterval, eToastPosition toastPosition)
        {
            return Show(parent, message, null, timeoutInterval, _DefaultToastGlowColor, toastPosition);
        }
        private static void CloseToast(ToastDisplay toast)
        {
            bool isTerminalSession = NativeFunctions.IsTerminalSession();
            if (toast.IsDisposed)
            {
                if (toast.Parent != null)
                    toast.Parent.Controls.Remove(toast);
                return;
            }
            if (isTerminalSession)
            {
                toast.Visible = false;
                toast.Parent.Controls.Remove(toast);
                toast.Dispose();
            }
            else
            {
                Animation.AnimationInt anim = new DevComponents.DotNetBar.Animation.AnimationInt(new Animation.AnimationRequest(toast, "Alpha", 255, 0),
                        Animation.AnimationEasing.EaseInQuad, 250);
                anim.AutoDispose = true;
                anim.Start();
                anim.AnimationCompleted += new EventHandler(delegate { if (toast.Parent != null) toast.Parent.Controls.Remove(toast); toast.Dispose(); });
            }
        }
        private static Padding _ToastMargin = new Padding(16);
        /// 
        /// Specifies the toast margin from the edges of the parent control. Default value is 16 pixels on all sides.
        /// 
        public static Padding ToastMargin
        {
            get
            {
                return _ToastMargin;
            }
            set
            {
                _ToastMargin = value;
            }
        }
        private static eToastPosition _DefaultToastPosition = eToastPosition.BottomCenter;
        /// 
        /// Specifies the default toast position within the parent control. Default value is BottomCenter.
        /// 
        public static eToastPosition DefaultToastPosition
        {
            get { return _DefaultToastPosition; }
            set { _DefaultToastPosition = value; }
        }
        private static eToastGlowColor _DefaultToastGlowColor = eToastGlowColor.Blue;
        /// 
        /// Specifies default glow color around toast notification. Default value is Blue.
        /// 
        public static eToastGlowColor DefaultToastGlowColor
        {
            get { return _DefaultToastGlowColor; }
            set { _DefaultToastGlowColor = value; }
        }
        private static int _DefaultTimeoutInterval = 2500;
        /// 
        /// Specifies the default timeout interval for the toast notification.
        /// 
        public static int DefaultTimeoutInterval
        {
            get { return _DefaultTimeoutInterval; }
            set
            {
                _DefaultTimeoutInterval = value;
            }
        }
        private static Color _ToastBackColor = Color.FromArgb (7, 7, 7);
        /// 
        /// Specifies the toast background color.
        /// 
        public static Color ToastBackColor
        {
            get { return _ToastBackColor; }
            set { _ToastBackColor = value; }
        }
        private static Color _ToastForeColor = Color.White;
        /// 
        /// Specifies the toast text color.
        /// 
        public static Color ToastForeColor
        {
            get { return _ToastForeColor; }
            set { _ToastForeColor = value; }
        }
        private static Font _ToastFont = null;
        /// 
        /// Specifies the font used for the toast.
        /// 
        public static Font ToastFont
        {
            get { return _ToastFont; }
            set { _ToastFont = value; }
        }
        private static Color _CustomGlowColor = Color.Brown;
        /// 
        /// Specifies the custom glow color used when eToastGlowColor.Custom is used.
        /// 
        public static Color CustomGlowColor
        {
            get { return _CustomGlowColor; }
            set { _CustomGlowColor = value; }
        }
    }
    /// 
    /// Specifies toast position within parent control.
    /// 
    public enum eToastPosition
    {
        TopLeft,
        TopCenter,
        TopRight,
        MiddleLeft,
        MiddleCenter,
        MiddleRight,
        BottomLeft,
        BottomCenter,
        BottomRight
    }
    /// 
    /// Specifies the glow color around toast notification.
    /// 
    public enum eToastGlowColor
    {
        None,
        Red,
        Blue,
        Green,
        Orange,
        Custom
    }
}