context: using System;
  using System.Windows.Forms;
  using System.Drawing;
  using System.ComponentModel;
  using System.Diagnostics.CodeAnalysis;
  
  namespace WeifenLuo.WinFormsUI.Docking {
  	public delegate string GetPersistStringCallback();
  
  	public class DockContentHandler : IDisposable, IDockDragSource {
  		public DockContentHandler(Form form)
  			: this(form, null) {
  		}
  
  		public DockContentHandler(Form form, GetPersistStringCallback getPersistStringCallback) {
  			if (!(form is IDockContent))
  				throw new ArgumentException(Strings.DockContent_Constructor_InvalidForm, "form");
  
  			m_form = form;
  			m_getPersistStringCallback = getPersistStringCallback;
  
  			m_events = new EventHandlerList();
  			Form.Disposed += new EventHandler(Form_Disposed);
  			Form.TextChanged += new EventHandler(Form_TextChanged);
  		}
  
  		public void Dispose() {
  			Dispose(true);
  			GC.SuppressFinalize(this);
  		}
  
  		protected virtual void Dispose(bool disposing) {
  			if (disposing) {
  				DockPanel = null;
  				if (m_autoHideTab != null)
  					m_autoHideTab.Dispose();
  				if (m_tab != null)
  					m_tab.Dispose();
  
  				Form.Disposed -= new EventHandler(Form_Disposed);
  				Form.TextChanged -= new EventHandler(Form_TextChanged);
  				m_events.Dispose();
  			}
  		}
  
  		private Form m_form;
  		public Form Form {
  			get { return m_form; }
  		}
  
  		public IDockContent Content {
  			get { return Form as IDockContent; }
  		}
  
  		private IDockContent m_previousActive = null;
  		public IDockContent PreviousActive {
  			get { return m_previousActive; }
  			internal set { m_previousActive = value; }
  		}
  
  		private IDockContent m_nextActive = null;
  		public IDockContent NextActive {
  			get { return m_nextActive; }
  			internal set { m_nextActive = value; }
  		}
  
  		private EventHandlerList m_events;
  		private EventHandlerList Events {
  			get { return m_events; }
  		}
  
  		private bool m_allowEndUserDocking = true;
  		public bool AllowEndUserDocking {
  			get { return m_allowEndUserDocking; }
  			set { m_allowEndUserDocking = value; }
  		}
  
  		private double m_autoHidePortion = 0.25;
  		public double AutoHidePortion {
  			get { return m_autoHidePortion; }
  			set {
  				if (value <= 0)
  					throw (new ArgumentOutOfRangeException(Strings.DockContentHandler_AutoHidePortion_OutOfRange));
  
  				if (m_autoHidePortion == value)
  					return;
  
  				m_autoHidePortion = value;
  
  				if (DockPanel == null)
  					return;
  
  				if (DockPanel.ActiveAutoHideContent == Content)
  					DockPanel.PerformLayout();
  			}
  		}
  
  		private bool m_closeButton = true;
  		public bool CloseButton {
  			get { return m_closeButton; }
  			set {
  				if (m_closeButton == value)
  					return;
  
  				m_closeButton = value;
  				if (IsActiveContentHandler)
  					Pane.RefreshChanges();
  			}
  		}
  
  		private bool m_closeButtonVisible = true;
  		/// <summary>
  		/// Determines whether the close button is visible on the content
  		/// </summary>
  		public bool CloseButtonVisible {
  			get { return m_closeButtonVisible; }
  			set {
  				if (m_closeButtonVisible == value)
  					return;
  
  				m_closeButtonVisible = value;
  				if (IsActiveContentHandler)
  					Pane.RefreshChanges();
  			}
  		}
  
  		private bool IsActiveContentHandler {
  			get { return Pane != null && Pane.ActiveContent != null && Pane.ActiveContent.DockHandler == this; }
  		}
  
  		private DockState DefaultDockState {
  			get {
  				if (ShowHint != DockState.Unknown && ShowHint != DockState.Hidden)
  					return ShowHint;
  
  				if ((DockAreas & DockAreas.Document) != 0)
  					return DockState.Document;
  				if ((DockAreas & DockAreas.DockRight) != 0)
  					return DockState.DockRight;
  				if ((DockAreas & DockAreas.DockLeft) != 0)
  					return DockState.DockLeft;
  				if ((DockAreas & DockAreas.DockBottom) != 0)
  					return DockState.DockBottom;
  				if ((DockAreas & DockAreas.DockTop) != 0)
  					return DockState.DockTop;
  
  				return DockState.Unknown;
  			}
  		}
  
  		private DockState DefaultShowState {
  			get {
  				if (ShowHint != DockState.Unknown)
  					return ShowHint;
  
  				if ((DockAreas & DockAreas.Document) != 0)
  					return DockState.Document;
  				if ((DockAreas & DockAreas.DockRight) != 0)
  					return DockState.DockRight;
  				if ((DockAreas & DockAreas.DockLeft) != 0)
  					return DockState.DockLeft;
  				if ((DockAreas & DockAreas.DockBottom) != 0)
  					return DockState.DockBottom;
  				if ((DockAreas & DockAreas.DockTop) != 0)
  					return DockState.DockTop;
  				if ((DockAreas & DockAreas.Float) != 0)
  					return DockState.Float;
  
  				return DockState.Unknown;
  			}
  		}
  
  		private DockAreas m_allowedAreas = DockAreas.DockLeft | DockAreas.DockRight | DockAreas.DockTop | DockAreas.DockBottom | DockAreas.Document | DockAreas.Float;
  		public DockAreas DockAreas {
  			get { return m_allowedAreas; }
  			set {
  				if (m_allowedAreas == value)
  					return;
  
  				if (!DockHelper.IsDockStateValid(DockState, value))
  					throw (new InvalidOperationException(Strings.DockContentHandler_DockAreas_InvalidValue));
  
  				m_allowedAreas = value;
  
  				if (!DockHelper.IsDockStateValid(ShowHint, m_allowedAreas))
  					ShowHint = DockState.Unknown;
  			}
  		}
  
  		private DockState m_dockState = DockState.Unknown;
  		public DockState DockState {
  			get { return m_dockState; }
  			set {
  				if (m_dockState == value)
  					return;
  
  				DockPanel.SuspendLayout(true);
  
  				if (value == DockState.Hidden)
  					IsHidden = true;
  				else
  					SetDockState(false, value, Pane);
  
  				DockPanel.ResumeLayout(true, true);
  			}
  		}
  
  		private DockPanel m_dockPanel = null;
  		public DockPanel DockPanel {
  			get { return m_dockPanel; }
  			set {
  				if (m_dockPanel == value) {
  					string msg = "if you have MainForm.PersistStringInstantiator() down the stack,"
  						+ " remove IDockContent.Show() for an instantiated form"
  						+ " and call it after whole layout will be restored!!!"
  						+ " Persistor.LoadFromXml() will throw if dockPanel.Content.Count < contentUnserialized.Count";
  					// added but decided not to use AddContent() since DockSample was throwing error on "m_SolitionExplorer.DockContent = null"... wtf
  					// and this code runs on MainForm.Dispose() during app close
  					//m_dockPanel.AddContent(Content);
  					return;
  				}
  				Pane = null;
  				if (m_dockPanel != null) {
  					string msg = "removing on DockPane.Close_Click() //why do you have to remove it? Huston will miss it later!";
  					m_dockPanel.RemoveContent(Content);
  				}
  				if (m_tab != null) {
  					m_tab.Dispose();
  					m_tab = null;
  				}
  				if (m_autoHideTab != null) {
  					m_autoHideTab.Dispose();
  					m_autoHideTab = null;
  				}
  				m_dockPanel = value;
  				if (m_dockPanel != null) {
  					m_dockPanel.AddContent(Content);
  					Form.TopLevel = false;
  					Form.FormBorderStyle = FormBorderStyle.None;
  					Form.ShowInTaskbar = false;
  					Form.WindowState = FormWindowState.Normal;
  					if (Win32Helper.IsRunningOnMono) return;
  					NativeMethods.SetWindowPos(Form.Handle, IntPtr.Zero, 0, 0, 0, 0,
  						Win32.FlagsSetWindowPos.SWP_NOACTIVATE |
  						Win32.FlagsSetWindowPos.SWP_NOMOVE |
  						Win32.FlagsSetWindowPos.SWP_NOSIZE |
  						Win32.FlagsSetWindowPos.SWP_NOZORDER |
  						Win32.FlagsSetWindowPos.SWP_NOOWNERZORDER |
  						Win32.FlagsSetWindowPos.SWP_FRAMECHANGED);
  				} else {
  					string msg = "removing on DockPane.Close_Click() //AddContent(Content) wasn't invoked => Huston will have problems";
  				}
  			}
  		}
  
  		public Icon Icon {
  			get { return Form.Icon; }
  		}
  
  		public DockPane Pane {
  			get { return IsFloat ? FloatPane : PanelPane; }
  			set {
  				if (Pane == value)
  					return;
  
  				DockPanel.SuspendLayout(true);
  
  				DockPane oldPane = Pane;
  
  				SuspendSetDockState();
  				FloatPane = (value == null ? null : (value.IsFloat ? value : FloatPane));
  				PanelPane = (value == null ? null : (value.IsFloat ? PanelPane : value));
  				ResumeSetDockState(IsHidden, value != null ? value.DockState : DockState.Unknown, oldPane);
  
  				DockPanel.ResumeLayout(true, true);
  			}
  		}
  
  		private bool m_isHidden = true;
  		public bool IsHidden {
  			get { return m_isHidden; }
  			set {
  				if (m_isHidden == value)return;
  				SetDockState(value, VisibleState, Pane);
  			}
  		}
  
  		private string m_tabText = null;
  		public string TabText {
  			get { return m_tabText == null || m_tabText == "" ? Form.Text : m_tabText; }
  			set {
  				if (m_tabText == value) return;
  				m_tabText = value;
  				if (Pane != null) Pane.RefreshChanges();
  			}
  		}
  
  		private DockState m_visibleState = DockState.Unknown;
  		public DockState VisibleState {
  			get { return m_visibleState; }
  			set { if (m_visibleState == value) return; }
  		}
  
  		private bool m_isFloat = false;
  		public bool IsFloat {
  			get { return m_isFloat; }
  			set {
  				if (m_isFloat == value) return;
  				DockState visibleState = CheckDockState(value);
  				if (visibleState == DockState.Unknown)
  					throw new InvalidOperationException(Strings.DockContentHandler_IsFloat_InvalidValue);
  
  				SetDockState(IsHidden, visibleState, Pane);
  			}
  		}
  
  		[SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")]
  		public DockState CheckDockState(bool isFloat) {
  			DockState dockState;
  
  			if (isFloat) {
  				if (!IsDockStateValid(DockState.Float))
  					dockState = DockState.Unknown;
  				else
  					dockState = DockState.Float;
  			} else {
  				dockState = (PanelPane != null) ? PanelPane.DockState : DefaultDockState;
  				if (dockState != DockState.Unknown && !IsDockStateValid(dockState))
  					dockState = DockState.Unknown;
  			}
  
  			return dockState;
  		}
  
  		private DockPane m_panelPane = null;
  		public DockPane PanelPane {
  			get { return m_panelPane; }
  			set {
  				if (m_panelPane == value)
  					return;
  
  				if (value != null) {
  					if (value.IsFloat || value.DockPanel != DockPanel)
  						throw new InvalidOperationException(Strings.DockContentHandler_DockPane_InvalidValue);
  				}
  
  				DockPane oldPane = Pane;
  
  				if (m_panelPane != null)
  					RemoveFromPane(m_panelPane);
  				m_panelPane = value;
  				if (m_panelPane != null) {
  					m_panelPane.AddContent(Content);
  					SetDockState(IsHidden, IsFloat ? DockState.Float : m_panelPane.DockState, oldPane);
  				} else
  					SetDockState(IsHidden, DockState.Unknown, oldPane);
  			}
  		}
  
  		private void RemoveFromPane(DockPane pane) {
  			pane.RemoveContent(Content);
  			SetPane(null);
  			if (pane.Contents.Count == 0)
  				pane.Dispose();
  		}
  
  		private DockPane m_floatPane = null;
  		public DockPane FloatPane {
  			get { return m_floatPane; }
  			set {
  				if (m_floatPane == value)
  					return;
  
  				if (value != null) {
  					if (!value.IsFloat || value.DockPanel != DockPanel)
  						throw new InvalidOperationException(Strings.DockContentHandler_FloatPane_InvalidValue);
  				}
  
  				DockPane oldPane = Pane;
  
  				if (m_floatPane != null)
  					RemoveFromPane(m_floatPane);
  				m_floatPane = value;
  				if (m_floatPane != null) {
  					m_floatPane.AddContent(Content);
  					SetDockState(IsHidden, IsFloat ? DockState.Float : VisibleState, oldPane);
  				} else
  					SetDockState(IsHidden, DockState.Unknown, oldPane);
  			}
  		}
  
  		private int m_countSetDockState = 0;
  		private void SuspendSetDockState() {
  			m_countSetDockState++;
  		}
  
  		private void ResumeSetDockState() {
  			m_countSetDockState--;
  			if (m_countSetDockState < 0)
  				m_countSetDockState = 0;
  		}
  
  		internal bool IsSuspendSetDockState {
  			get { return m_countSetDockState != 0; }
  		}
  
  		private void ResumeSetDockState(bool isHidden, DockState visibleState, DockPane oldPane) {
  			ResumeSetDockState();
  
gt: 			SetDockState(isHidden, visibleState, oldPane);