// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.

using System;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using System.Windows.Forms;
using OpenLiveWriter.CoreServices;
using OpenLiveWriter.Interop.Windows;

namespace OpenLiveWriter.Controls
{

    /// <summary>
    /// Summary description for DelayedFetchComboBox.
    /// </summary>
    public class DelayedFetchComboBox : ComboBox
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        private IDelayedFetchHandler _fetchHandler;
        private DropDownNotifier _dropDownNotifier;

        public DelayedFetchComboBox(System.ComponentModel.IContainer container)
        {
            ///
            /// Required for Windows.Forms Class Composition Designer support
            ///
            container.Add(this);
            InitializeComponent();
        }

        public DelayedFetchComboBox()
        {
            ///
            /// Required for Windows.Forms Class Composition Designer support
            ///
            InitializeComponent();

            //
            // TODO: Add any constructor code after InitializeComponent call
            //
        }

        public void Initialize(object initialValue, IDelayedFetchHandler fetchHandler)
        {
            Initialize(new object[] { initialValue }, initialValue, fetchHandler);
        }

        public void Initialize(object[] items, object initialValue, IDelayedFetchHandler fetchHandler)
        {
            Items.Clear();
            Items.AddRange(items);
            SelectedItem = initialValue;
            _fetchHandler = fetchHandler;
        }

        /// <summary>
        /// Notification that the combo is dropping down.
        /// </summary>
        private void ComboDroppingDown()
        {
            if (_fetchHandler != null)
            {
                using (new WaitCursor())
                {
                    // attempt to fetch items
                    object[] items = _fetchHandler.FetchItems(FindForm());

                    // if we got some items then merge them with the existing combo
                    // and then disable fetching for this session
                    if (items != null)
                    {
                        foreach (object item in items)
                        {
                            if (!Items.Contains(item))
                                Items.Add(item);
                        }

                        _fetchHandler = null;
                    }
                }
            }
        }

        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);

            if (Parent != null)
            {
                if (Parent.IsHandleCreated)
                    InstallDropDownNotifier();
                else
                    Parent.HandleCreated += new EventHandler(Parent_HandleCreated);
            }
            else
            {
                RemoveDropDownNotifier();
            }
        }

        private void Parent_HandleCreated(object sender, EventArgs e)
        {
            Parent.HandleCreated -= new EventHandler(Parent_HandleCreated);
            InstallDropDownNotifier();
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                RemoveDropDownNotifier();

                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        private void InstallDropDownNotifier()
        {
            RemoveDropDownNotifier();
            _dropDownNotifier = new DropDownNotifier(this);
        }

        private void RemoveDropDownNotifier()
        {
            if (_dropDownNotifier != null)
            {
                _dropDownNotifier.Dispose();
                _dropDownNotifier = null;
            }
        }

        private class DropDownNotifier : NativeWindow, IDisposable
        {
            public DropDownNotifier(DelayedFetchComboBox delayedFetchCombo)
            {
                _delayedFetchCombo = delayedFetchCombo;
                AssignHandle(delayedFetchCombo.Parent.Handle);
            }

            protected override void WndProc(ref Message m)
            {
                // notify combo that it is dropping down
                if (m.Msg == WM.COMMAND && MessageHelper.HIWORDToInt32(m.WParam) == CBN.DROPDOWN)
                {
                    try
                    {
                        _delayedFetchCombo.ComboDroppingDown();
                    }
                    catch (Exception ex)
                    {
                        Trace.Fail("Unexpected exception processing combo drop down: " + ex.ToString());
                    }
                }

                // always call base
                base.WndProc(ref m);
            }

            public void Dispose()
            {
                ReleaseHandle();
            }

            private DelayedFetchComboBox _delayedFetchCombo;

        }

        #region Component Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            //
            // DelayedFetchComboBox
            //

        }
        #endregion

    }

    public interface IDelayedFetchHandler
    {
        object[] FetchItems(IWin32Window owner);
    }

}