// 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) ;
	}

}
