using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace MyAuth
{
    /// <summary>
    /// Class used to display a modal dialog.
    /// The content is specified in the <see cref="Show"/> method.
    /// </summary>
    public partial class ModalDialog : UserControl
    {
        //-------------------------------------------------------------------
        #region ** fields

        FrameworkElement _root;
        Popup _popup;

        #endregion

        //-------------------------------------------------------------------
        #region ** ctor

        /// <summary>
        /// Initializes a new instance of a <see cref="ModalDialog"/>.
        /// </summary>
        /// <remarks>
        /// This constructor is private. Use the static Show method to
        /// instantiate and display modal dialogs.
        /// </remarks>
        private ModalDialog()
        {
            InitializeComponent();
            _popup = new Popup();
            _popup.Child = this;
            _btnClose.Click += (s, e) => { _popup.IsOpen = false; };
        }

        #endregion

        //-------------------------------------------------------------------
        #region ** object model

        /// <summary>
        /// Creates and displays a new <see cref="ModalDialog"/>.
        /// </summary>
        public static void Show(FrameworkElement owner, string caption, FrameworkElement content)
        {
            // create dialog
            var dlg = new ModalDialog();

            // set dialog's data context
            if (owner != null)
            {
                dlg.DataContext = owner.DataContext;
            }

            // check that the DataContext is an AuthenticationModel
            var model = dlg.DataContext as AuthenticationModel;
            if (model == null)
            {
                throw new Exception("DataContext should be set to an AuthenticationModel.");
            }

            // set dialog's font
            var ctl = owner as Control;
            if (ctl != null)
            {
                dlg.FontFamily = ctl.FontFamily;
                dlg.FontSize = ctl.FontSize;
            }

            // show dialog
            dlg.Show(caption, content);
        }
        /// <summary>
        /// Closes the dialog that contains a given element.
        /// </summary>
        public static void Close(FrameworkElement e)
        {
            var dlg = GetDialog(e);
            if (dlg != null)
            {
                dlg.Close();
            }
        }
        /// <summary>
        /// Changes the UI to indicate an async operation has started.
        /// </summary>
        public static void StartOperation(Control ctl)
        {
            ctl.IsEnabled = false;
            GetDialog(ctl).Cursor = Cursors.Wait;
        }
        /// <summary>
        /// Changes the UI to indicate an async operation has completed.
        /// </summary>
        public static void EndOperation(Control ctl, Exception x)
        {
            var dlg = GetDialog(ctl);
            if (x == null)
            {
                dlg.Close();
            }
            else
            {
                // re-enable dialog
                dlg.Cursor = null;
                ctl.IsEnabled = true;

                // show error message
                var tb = dlg._tbErrorMsg;
                tb.Text = x.Message;
                tb.Visibility = Visibility.Visible;
            }
        }

        #endregion

        //-------------------------------------------------------------------
        #region ** implementation

        // show the dialog
        void Show(string caption, FrameworkElement content)
        {
            // fill root visual
            if (_root == null)
            {
                _root = Application.Current.RootVisual as FrameworkElement;
                _root.LayoutUpdated += (s, e) =>
                    {
                        var sz = _root.RenderSize;
                        Width = sz.Width;
                        Height = sz.Height;
                    };
            }

            // add caption and content
            _tbCaption.Text = caption;
            _bdrContent.Child = content;

            // show the dialog
            _popup.IsOpen = true;

            // limit width of error message element
            UpdateLayout();
            _tbErrorMsg.MaxWidth = content.ActualWidth;

            // give focus to content
            var ctl = content as Control;
            if (ctl != null)
            {
                ctl.Focus();
            }
        }

        // close the dialog
        void Close()
        {
            _popup.IsOpen = false;
        }

        // gets the ModalDialog that contains the given element
        static ModalDialog GetDialog(FrameworkElement e)
        {
            for (var p = e; p != null; p = p.Parent as FrameworkElement)
            {
                var dlg = p as ModalDialog;
                if (dlg != null)
                {
                    return dlg;
                }
            }
            return null;
        }

        #endregion
    }
}
