/*************************************************************************************

   Extended WPF Toolkit

   Copyright (C) 2007-2013 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license 

   For more features, controls, and fast professional support,
   pick up the Plus Edition at http://xceed.com/wpf_toolkit

   Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids

  ***********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Xceed.Wpf.AvalonDock.Layout;
using System.Windows.Input;
using Xceed.Wpf.AvalonDock.Commands;
using System.ComponentModel;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Controls;

namespace Xceed.Wpf.AvalonDock.Controls
{
    public abstract class LayoutItem : FrameworkElement
    {
        static LayoutItem()
        { 
            ToolTipProperty.OverrideMetadata(typeof(LayoutItem), new FrameworkPropertyMetadata(null, (s, e) => OnToolTipChanged(s,e)));
            VisibilityProperty.OverrideMetadata(typeof(LayoutItem), new FrameworkPropertyMetadata(Visibility.Visible, (s,e) => OnVisibilityChanged(s, e)));
        }


        internal LayoutItem()
        {

        }

        internal virtual void Attach(LayoutContent model)
        { 
            LayoutElement = model;
            Model = model.Content;

            InitDefaultCommands();

            LayoutElement.IsSelectedChanged+=new EventHandler(LayoutElement_IsSelectedChanged);
            LayoutElement.IsActiveChanged+=new EventHandler(LayoutElement_IsActiveChanged);

            DataContext = this;
        }



        void LayoutElement_IsActiveChanged(object sender, EventArgs e)
        {
            if (_isActiveReentrantFlag.CanEnter)
            {
                using (_isActiveReentrantFlag.Enter())
                {
                    var bnd = BindingOperations.GetBinding(this, IsActiveProperty);
                    IsActive = LayoutElement.IsActive;
                    var bnd2 = BindingOperations.GetBinding(this, IsActiveProperty);
                }
            }
        }

        void LayoutElement_IsSelectedChanged(object sender, EventArgs e)
        {
            if (_isSelectedReentrantFlag.CanEnter)
            {
                using (_isSelectedReentrantFlag.Enter())
                {
                    IsSelected = LayoutElement.IsSelected;
                }
            }
        }

        internal virtual void Detach()
        {
            LayoutElement.IsSelectedChanged -= new EventHandler(LayoutElement_IsSelectedChanged);
            LayoutElement.IsActiveChanged -= new EventHandler(LayoutElement_IsActiveChanged);
            LayoutElement = null;
            Model = null;
        }

        public LayoutContent LayoutElement
        {
            get;
            private set;
        }

        public object Model
        {
            get;
            private set;
        }

        ICommand _defaultCloseCommand;
        ICommand _defaultFloatCommand;
        ICommand _defaultDockAsDocumentCommand;
        ICommand _defaultCloseAllButThisCommand;
        ICommand _defaultCloseAllCommand;
        ICommand _defaultActivateCommand;
        ICommand _defaultNewVerticalTabGroupCommand;
        ICommand _defaultNewHorizontalTabGroupCommand;
        ICommand _defaultMoveToNextTabGroupCommand;
        ICommand _defaultMoveToPreviousTabGroupCommand;

        protected virtual void InitDefaultCommands()
        {
            _defaultCloseCommand = new RelayCommand((p) => ExecuteCloseCommand(p), (p) => CanExecuteCloseCommand(p));
            _defaultFloatCommand = new RelayCommand((p) => ExecuteFloatCommand(p), (p) => CanExecuteFloatCommand(p));
            _defaultDockAsDocumentCommand = new RelayCommand((p) => ExecuteDockAsDocumentCommand(p), (p) => CanExecuteDockAsDocumentCommand(p));
            _defaultCloseAllButThisCommand = new RelayCommand((p) => ExecuteCloseAllButThisCommand(p), (p) => CanExecuteCloseAllButThisCommand(p));
            _defaultCloseAllCommand = new RelayCommand( ( p ) => ExecuteCloseAllCommand( p ), ( p ) => CanExecuteCloseAllCommand( p ) );
            _defaultActivateCommand = new RelayCommand( ( p ) => ExecuteActivateCommand( p ), ( p ) => CanExecuteActivateCommand( p ) );
            _defaultNewVerticalTabGroupCommand = new RelayCommand((p) => ExecuteNewVerticalTabGroupCommand(p), (p) => CanExecuteNewVerticalTabGroupCommand(p));
            _defaultNewHorizontalTabGroupCommand = new RelayCommand((p) => ExecuteNewHorizontalTabGroupCommand(p), (p) => CanExecuteNewHorizontalTabGroupCommand(p));
            _defaultMoveToNextTabGroupCommand = new RelayCommand((p) => ExecuteMoveToNextTabGroupCommand(p), (p) => CanExecuteMoveToNextTabGroupCommand(p));
            _defaultMoveToPreviousTabGroupCommand = new RelayCommand((p) => ExecuteMoveToPreviousTabGroupCommand(p), (p) => CanExecuteMoveToPreviousTabGroupCommand(p));
        }

        protected virtual void ClearDefaultBindings()
        {
            if (CloseCommand == _defaultCloseCommand)
                BindingOperations.ClearBinding(this, CloseCommandProperty);
            if (FloatCommand == _defaultFloatCommand)
                BindingOperations.ClearBinding(this, FloatCommandProperty);
            if (DockAsDocumentCommand == _defaultDockAsDocumentCommand)
                BindingOperations.ClearBinding(this, DockAsDocumentCommandProperty);
            if (CloseAllButThisCommand == _defaultCloseAllButThisCommand)
                BindingOperations.ClearBinding(this, CloseAllButThisCommandProperty);
            if( CloseAllCommand == _defaultCloseAllCommand )
              BindingOperations.ClearBinding( this, CloseAllCommandProperty );
            if (ActivateCommand == _defaultActivateCommand)
                BindingOperations.ClearBinding(this, ActivateCommandProperty);
            if (NewVerticalTabGroupCommand == _defaultNewVerticalTabGroupCommand)
                BindingOperations.ClearBinding(this, NewVerticalTabGroupCommandProperty);
            if (NewHorizontalTabGroupCommand == _defaultNewHorizontalTabGroupCommand)
                BindingOperations.ClearBinding(this, NewHorizontalTabGroupCommandProperty);
            if (MoveToNextTabGroupCommand == _defaultMoveToNextTabGroupCommand)
                BindingOperations.ClearBinding(this, MoveToNextTabGroupCommandProperty);
            if (MoveToPreviousTabGroupCommand == _defaultMoveToPreviousTabGroupCommand)
                BindingOperations.ClearBinding(this, MoveToPreviousTabGroupCommandProperty);
        }

        protected virtual void SetDefaultBindings()
        {
            if (CloseCommand == null)
                CloseCommand = _defaultCloseCommand;
            if (FloatCommand == null)
                FloatCommand = _defaultFloatCommand;
            if (DockAsDocumentCommand == null)
                DockAsDocumentCommand = _defaultDockAsDocumentCommand;
            if (CloseAllButThisCommand == null)
                CloseAllButThisCommand = _defaultCloseAllButThisCommand;
            if( CloseAllCommand == null )
                CloseAllCommand = _defaultCloseAllCommand;
            if (ActivateCommand == null)
                ActivateCommand = _defaultActivateCommand;
            if (NewVerticalTabGroupCommand == null)
                NewVerticalTabGroupCommand = _defaultNewVerticalTabGroupCommand;
            if (NewHorizontalTabGroupCommand == null)
                NewHorizontalTabGroupCommand = _defaultNewHorizontalTabGroupCommand;
            if (MoveToNextTabGroupCommand == null)
                MoveToNextTabGroupCommand = _defaultMoveToNextTabGroupCommand;
            if (MoveToPreviousTabGroupCommand == null)
                MoveToPreviousTabGroupCommand = _defaultMoveToPreviousTabGroupCommand;


            IsSelected = LayoutElement.IsSelected;
            IsActive = LayoutElement.IsActive;
        }

        internal void _ClearDefaultBindings()
        {
            ClearDefaultBindings();
        }

        internal void _SetDefaultBindings()
        {
            SetDefaultBindings();
        }

        internal bool IsViewExists()
        {
          return (_view != null);
        }

        ContentPresenter _view = null;
        public ContentPresenter View
        {
            get
            {
                if (_view == null)
                {
                    _view = new ContentPresenter();

                    _view.SetBinding(ContentPresenter.ContentProperty, new Binding("Content") { Source = LayoutElement });
                    _view.SetBinding( ContentPresenter.ContentTemplateProperty, new Binding( "LayoutItemTemplate" ) { Source = LayoutElement.Root.Manager } );
                    _view.SetBinding( ContentPresenter.ContentTemplateSelectorProperty, new Binding( "LayoutItemTemplateSelector" ) { Source = LayoutElement.Root.Manager } );
                    LayoutElement.Root.Manager.InternalAddLogicalChild( _view );
                }

                return _view;
            }
        }


        #region Title

        /// <summary>
        /// Title Dependency Property
        /// </summary>
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(LayoutItem),
                new FrameworkPropertyMetadata((string)null,
                    new PropertyChangedCallback(OnTitleChanged)));

        /// <summary>
        /// Gets or sets the Title property.  This dependency property 
        /// indicates the title of the element.
        /// </summary>
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        /// <summary>
        /// Handles changes to the Title property.
        /// </summary>
        private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnTitleChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the Title property.
        /// </summary>
        protected virtual void OnTitleChanged(DependencyPropertyChangedEventArgs e)
        {
            if (LayoutElement != null)
                LayoutElement.Title = (string)e.NewValue;
        }

        #endregion

        #region ToolTip
        private static void OnToolTipChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)s).OnToolTipChanged();
        }

        private void OnToolTipChanged()
        {
            if (LayoutElement != null)
                LayoutElement.ToolTip = ToolTip;
        }
        #endregion

        #region IconSource

        /// <summary>
        /// IconSource Dependency Property
        /// </summary>
        public static readonly DependencyProperty IconSourceProperty =
            DependencyProperty.Register("IconSource", typeof(ImageSource), typeof(LayoutItem),
                new FrameworkPropertyMetadata((ImageSource)null,
                    new PropertyChangedCallback(OnIconSourceChanged)));

        /// <summary>
        /// Gets or sets the IconSource property.  This dependency property 
        /// indicates icon associated with the item.
        /// </summary>
        public ImageSource IconSource
        {
            get { return (ImageSource)GetValue(IconSourceProperty); }
            set { SetValue(IconSourceProperty, value); }
        }

        /// <summary>
        /// Handles changes to the IconSource property.
        /// </summary>
        private static void OnIconSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnIconSourceChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IconSource property.
        /// </summary>
        protected virtual void OnIconSourceChanged(DependencyPropertyChangedEventArgs e)
        {
            if (LayoutElement != null)
                LayoutElement.IconSource = IconSource;
        }

        #endregion

        #region Visibility

        private static void OnVisibilityChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)s).OnVisibilityChanged();
        }

        protected virtual void OnVisibilityChanged()
        {
            if (LayoutElement != null &&
                Visibility == System.Windows.Visibility.Collapsed)
                LayoutElement.Close();
        }

        #endregion

        #region ContentId

        /// <summary>
        /// ContentId Dependency Property
        /// </summary>
        public static readonly DependencyProperty ContentIdProperty =
            DependencyProperty.Register("ContentId", typeof(string), typeof(LayoutItem),
                new FrameworkPropertyMetadata((string)null,
                    new PropertyChangedCallback(OnContentIdChanged)));

        /// <summary>
        /// Gets or sets the ContentId property.  This dependency property 
        /// indicates the content id used to retrive content when deserializing layouts.
        /// </summary>
        public string ContentId
        {
            get { return (string)GetValue(ContentIdProperty); }
            set { SetValue(ContentIdProperty, value); }
        }

        /// <summary>
        /// Handles changes to the ContentId property.
        /// </summary>
        private static void OnContentIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnContentIdChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the ContentId property.
        /// </summary>
        protected virtual void OnContentIdChanged(DependencyPropertyChangedEventArgs e)
        {
            if (LayoutElement != null)
                LayoutElement.ContentId = (string)e.NewValue;
        }

        #endregion

        #region IsSelected

        ReentrantFlag _isSelectedReentrantFlag = new ReentrantFlag();

        /// <summary>
        /// IsSelected Dependency Property
        /// </summary>
        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register("IsSelected", typeof(bool), typeof(LayoutItem),
                new FrameworkPropertyMetadata((bool)false,
                    new PropertyChangedCallback(OnIsSelectedChanged)));

        /// <summary>
        /// Gets or sets the IsSelected property.  This dependency property 
        /// indicates if the item is selected inside its container.
        /// </summary>
        public bool IsSelected
        {
            get { return (bool)GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        }

        /// <summary>
        /// Handles changes to the IsSelected property.
        /// </summary>
        private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnIsSelectedChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IsSelected property.
        /// </summary>
        protected virtual void OnIsSelectedChanged(DependencyPropertyChangedEventArgs e)
        {
            if (_isSelectedReentrantFlag.CanEnter)
            {
                using (_isSelectedReentrantFlag.Enter())
                {
                    if (LayoutElement != null)
                        LayoutElement.IsSelected = (bool)e.NewValue;
                }
            }
        }

        #endregion

        #region IsActive

        ReentrantFlag _isActiveReentrantFlag = new ReentrantFlag();

        /// <summary>
        /// IsActive Dependency Property
        /// </summary>
        public static readonly DependencyProperty IsActiveProperty =
            DependencyProperty.Register("IsActive", typeof(bool), typeof(LayoutItem),
                new FrameworkPropertyMetadata((bool)false,
                    new PropertyChangedCallback(OnIsActiveChanged)));

        /// <summary>
        /// Gets or sets the IsActive property.  This dependency property 
        /// indicates if the item is active in the UI.
        /// </summary>
        public bool IsActive
        {
            get { return (bool)GetValue(IsActiveProperty); }
            set { SetValue(IsActiveProperty, value); }
        }

        /// <summary>
        /// Handles changes to the IsActive property.
        /// </summary>
        private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnIsActiveChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IsActive property.
        /// </summary>
        protected virtual void OnIsActiveChanged(DependencyPropertyChangedEventArgs e)
        {
            if (_isActiveReentrantFlag.CanEnter)
            {
                using (_isActiveReentrantFlag.Enter())
                {
                    if (LayoutElement != null)
                        LayoutElement.IsActive = (bool)e.NewValue;
                }
            }
        }

        #endregion

        #region CanClose

        /// <summary>
        /// CanClose Dependency Property
        /// </summary>
        public static readonly DependencyProperty CanCloseProperty =
            DependencyProperty.Register("CanClose", typeof(bool), typeof(LayoutItem),
                new FrameworkPropertyMetadata((bool)true,
                    new PropertyChangedCallback(OnCanCloseChanged)));

        /// <summary>
        /// Gets or sets the CanClose property.  This dependency property 
        /// indicates if the item can be closed.
        /// </summary>
        public bool CanClose
        {
            get { return (bool)GetValue(CanCloseProperty); }
            set { SetValue(CanCloseProperty, value); }
        }

        /// <summary>
        /// Handles changes to the CanClose property.
        /// </summary>
        private static void OnCanCloseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnCanCloseChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the CanClose property.
        /// </summary>
        protected virtual void OnCanCloseChanged(DependencyPropertyChangedEventArgs e)
        {
            if (LayoutElement != null)
                LayoutElement.CanClose = (bool)e.NewValue;
        }

        #endregion

        #region CanFloat

        /// <summary>
        /// CanFloat Dependency Property
        /// </summary>
        public static readonly DependencyProperty CanFloatProperty =
            DependencyProperty.Register("CanFloat", typeof(bool), typeof(LayoutItem),
                new FrameworkPropertyMetadata((bool)true,
                    new PropertyChangedCallback(OnCanFloatChanged)));

        /// <summary>
        /// Gets or sets the CanFloat property.  This dependency property 
        /// indicates if user can move the layout element dragging it to another position.
        /// </summary>
        public bool CanFloat
        {
            get { return (bool)GetValue(CanFloatProperty); }
            set { SetValue(CanFloatProperty, value); }
        }

        /// <summary>
        /// Handles changes to the CanFloat property.
        /// </summary>
        private static void OnCanFloatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnCanFloatChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the CanFloat property.
        /// </summary>
        protected virtual void OnCanFloatChanged(DependencyPropertyChangedEventArgs e)
        {
            if (LayoutElement != null)
                LayoutElement.CanFloat = (bool)e.NewValue;
        }

        #endregion

        #region CloseCommand

        /// <summary>
        /// CloseCommand Dependency Property
        /// </summary>
        public static readonly DependencyProperty CloseCommandProperty =
            DependencyProperty.Register("CloseCommand", typeof(ICommand), typeof(LayoutItem),
                new FrameworkPropertyMetadata(null,
                    new PropertyChangedCallback(OnCloseCommandChanged),
                    new CoerceValueCallback(CoerceCloseCommandValue)));

        /// <summary>
        /// Gets or sets the CloseCommand property.  This dependency property 
        /// indicates the command to execute when user click the document close button.
        /// </summary>
        public ICommand CloseCommand
        {
            get { return (ICommand)GetValue(CloseCommandProperty); }
            set { SetValue(CloseCommandProperty, value); }
        }

        /// <summary>
        /// Handles changes to the CloseCommand property.
        /// </summary>
        private static void OnCloseCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnCloseCommandChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the CloseCommand property.
        /// </summary>
        protected virtual void OnCloseCommandChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        /// <summary>
        /// Coerces the CloseCommand value.
        /// </summary>
        private static object CoerceCloseCommandValue(DependencyObject d, object value)
        {
            return value;
        }

        private bool CanExecuteCloseCommand(object parameter)
        {
            return LayoutElement != null && LayoutElement.CanClose;
        }

        private void ExecuteCloseCommand(object parameter)
        {
            Close();
        }

        protected abstract void Close();


        #endregion

        #region FloatCommand
        /// <summary>
        /// FloatCommand Dependency Property
        /// </summary>
        public static readonly DependencyProperty FloatCommandProperty =
            DependencyProperty.Register("FloatCommand", typeof(ICommand), typeof(LayoutItem),
                new FrameworkPropertyMetadata(null,
                    new PropertyChangedCallback(OnFloatCommandChanged),
                    new CoerceValueCallback(CoerceFloatCommandValue)));

        /// <summary>
        /// Gets or sets the FloatCommand property.  This dependency property 
        /// indicates the command to execute when user click the float button.
        /// </summary>
        /// <remarks>By default this command move the anchorable inside new floating window.</remarks>
        public ICommand FloatCommand
        {
            get { return (ICommand)GetValue(FloatCommandProperty); }
            set { SetValue(FloatCommandProperty, value); }
        }

        /// <summary>
        /// Handles changes to the FloatCommand property.
        /// </summary>
        private static void OnFloatCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnFloatCommandChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the FloatCommand property.
        /// </summary>
        protected virtual void OnFloatCommandChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        /// <summary>
        /// Coerces the FloatCommand value.
        /// </summary>
        private static object CoerceFloatCommandValue(DependencyObject d, object value)
        {
            return value;
        }

        private bool CanExecuteFloatCommand(object anchorable)
        {
            return LayoutElement != null && LayoutElement.CanFloat && LayoutElement.FindParent<LayoutFloatingWindow>() == null;
        }

        private void ExecuteFloatCommand(object parameter)
        {
            LayoutElement.Root.Manager._ExecuteFloatCommand(LayoutElement);
        }

        protected virtual void Float()
        { 

        }

        #endregion

        #region DockAsDocumentCommand

        /// <summary>
        /// DockAsDocumentCommand Dependency Property
        /// </summary>
        public static readonly DependencyProperty DockAsDocumentCommandProperty =
            DependencyProperty.Register("DockAsDocumentCommand", typeof(ICommand), typeof(LayoutItem),
                new FrameworkPropertyMetadata(null,
                    new PropertyChangedCallback(OnDockAsDocumentCommandChanged),
                    new CoerceValueCallback(CoerceDockAsDocumentCommandValue)));

        /// <summary>
        /// Gets or sets the DockAsDocumentCommand property.  This dependency property 
        /// indicates the command to execute when user click the DockAsDocument button.
        /// </summary>
        /// <remarks>By default this command move the anchorable inside the last focused document pane.</remarks>
        public ICommand DockAsDocumentCommand
        {
            get { return (ICommand)GetValue(DockAsDocumentCommandProperty); }
            set { SetValue(DockAsDocumentCommandProperty, value); }
        }

        /// <summary>
        /// Handles changes to the DockAsDocumentCommand property.
        /// </summary>
        private static void OnDockAsDocumentCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnDockAsDocumentCommandChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the DockAsDocumentCommand property.
        /// </summary>
        protected virtual void OnDockAsDocumentCommandChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        /// <summary>
        /// Coerces the DockAsDocumentCommand value.
        /// </summary>
        private static object CoerceDockAsDocumentCommandValue(DependencyObject d, object value)
        {
            return value;
        }

        private bool CanExecuteDockAsDocumentCommand(object parameter)
        {
            return LayoutElement != null && LayoutElement.FindParent<LayoutDocumentPane>() == null;
        }

        private void ExecuteDockAsDocumentCommand(object parameter)
        {
            LayoutElement.Root.Manager._ExecuteDockAsDocumentCommand(LayoutElement);
        }

        #endregion

        #region CloseAllButThisCommand

        /// <summary>
        /// CloseAllButThisCommand Dependency Property
        /// </summary>
        public static readonly DependencyProperty CloseAllButThisCommandProperty =
            DependencyProperty.Register("CloseAllButThisCommand", typeof(ICommand), typeof(LayoutItem),
                new FrameworkPropertyMetadata(null,
                    new PropertyChangedCallback(OnCloseAllButThisCommandChanged),
                    new CoerceValueCallback(CoerceCloseAllButThisCommandValue)));

        /// <summary>
        /// Gets or sets the CloseAllButThisCommand property.  This dependency property 
        /// indicates the 'Close All But This' command.
        /// </summary>
        public ICommand CloseAllButThisCommand
        {
            get { return (ICommand)GetValue(CloseAllButThisCommandProperty); }
            set { SetValue(CloseAllButThisCommandProperty, value); }
        }

        /// <summary>
        /// Handles changes to the CloseAllButThisCommand property.
        /// </summary>
        private static void OnCloseAllButThisCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnCloseAllButThisCommandChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the CloseAllButThisCommand property.
        /// </summary>
        protected virtual void OnCloseAllButThisCommandChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        /// <summary>
        /// Coerces the CloseAllButThisCommand value.
        /// </summary>
        private static object CoerceCloseAllButThisCommandValue(DependencyObject d, object value)
        {
            return value;
        }

        private bool CanExecuteCloseAllButThisCommand(object parameter)
        {
            if (LayoutElement == null)
                return false;
            var root = LayoutElement.Root;
            if (root == null)
                return false;

            return LayoutElement.Root.Manager.Layout.
                Descendents().OfType<LayoutContent>().Where(d => d != LayoutElement && (d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow)).Any();
        }

        private void ExecuteCloseAllButThisCommand(object parameter)
        {
            LayoutElement.Root.Manager._ExecuteCloseAllButThisCommand(LayoutElement);
        }

        #endregion

        #region CloseAllCommand

        /// <summary>
        /// CloseAllCommand Dependency Property
        /// </summary>
        public static readonly DependencyProperty CloseAllCommandProperty =
            DependencyProperty.Register( "CloseAllCommand", typeof( ICommand ), typeof( LayoutItem ),
                new FrameworkPropertyMetadata( null,
                    new PropertyChangedCallback( OnCloseAllCommandChanged ),
                    new CoerceValueCallback( CoerceCloseAllCommandValue ) ) );

        /// <summary>
        /// Gets or sets the CloseAllCommand property.  This dependency property 
        /// indicates the 'Close All' command.
        /// </summary>
        public ICommand CloseAllCommand
        {
          get
          {
            return ( ICommand )GetValue( CloseAllCommandProperty );
          }
          set
          {
            SetValue( CloseAllCommandProperty, value );
          }
        }

        /// <summary>
        /// Handles changes to the CloseAllCommand property.
        /// </summary>
        private static void OnCloseAllCommandChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
          ( ( LayoutItem )d ).OnCloseAllCommandChanged( e );
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the CloseAllCommand property.
        /// </summary>
        protected virtual void OnCloseAllCommandChanged( DependencyPropertyChangedEventArgs e )
        {
        }

        /// <summary>
        /// Coerces the CloseAllCommand value.
        /// </summary>
        private static object CoerceCloseAllCommandValue( DependencyObject d, object value )
        {
          return value;
        }

        private bool CanExecuteCloseAllCommand( object parameter )
        {
          if( LayoutElement == null )
            return false;
          var root = LayoutElement.Root;
          if( root == null )
            return false;

          return LayoutElement.Root.Manager.Layout.
              Descendents().OfType<LayoutContent>().Where( d => ( d.Parent is LayoutDocumentPane || d.Parent is LayoutDocumentFloatingWindow ) ).Any();
        }

        private void ExecuteCloseAllCommand( object parameter )
        {
          LayoutElement.Root.Manager._ExecuteCloseAllCommand( LayoutElement );
        }

        #endregion

        #region ActivateCommand

        /// <summary>
        /// ActivateCommand Dependency Property
        /// </summary>
        public static readonly DependencyProperty ActivateCommandProperty =
            DependencyProperty.Register("ActivateCommand", typeof(ICommand), typeof(LayoutItem),
                new FrameworkPropertyMetadata(null,
                    new PropertyChangedCallback(OnActivateCommandChanged),
                    new CoerceValueCallback(CoerceActivateCommandValue)));

        /// <summary>
        /// Gets or sets the ActivateCommand property.  This dependency property 
        /// indicates the command to execute when user wants to activate a content (either a Document or an Anchorable).
        /// </summary>
        public ICommand ActivateCommand
        {
            get { return (ICommand)GetValue(ActivateCommandProperty); }
            set { SetValue(ActivateCommandProperty, value); }
        }

        /// <summary>
        /// Handles changes to the ActivateCommand property.
        /// </summary>
        private static void OnActivateCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnActivateCommandChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the ActivateCommand property.
        /// </summary>
        protected virtual void OnActivateCommandChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        /// <summary>
        /// Coerces the ActivateCommand value.
        /// </summary>
        private static object CoerceActivateCommandValue(DependencyObject d, object value)
        {
            return value;
        }

        private bool CanExecuteActivateCommand(object parameter)
        {
            return LayoutElement != null;
        }

        private void ExecuteActivateCommand(object parameter)
        {
            LayoutElement.Root.Manager._ExecuteContentActivateCommand(LayoutElement);
        }

        #endregion

        #region NewVerticalTabGroupCommand

        /// <summary>
        /// NewVerticalTabGroupCommand Dependency Property
        /// </summary>
        public static readonly DependencyProperty NewVerticalTabGroupCommandProperty =
            DependencyProperty.Register("NewVerticalTabGroupCommand", typeof(ICommand), typeof(LayoutItem),
                new FrameworkPropertyMetadata((ICommand)null,
                    new PropertyChangedCallback(OnNewVerticalTabGroupCommandChanged)));

        /// <summary>
        /// Gets or sets the NewVerticalTabGroupCommand property.  This dependency property 
        /// indicates the new vertical tab group command.
        /// </summary>
        public ICommand NewVerticalTabGroupCommand
        {
            get { return (ICommand)GetValue(NewVerticalTabGroupCommandProperty); }
            set { SetValue(NewVerticalTabGroupCommandProperty, value); }
        }

        /// <summary>
        /// Handles changes to the NewVerticalTabGroupCommand property.
        /// </summary>
        private static void OnNewVerticalTabGroupCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnNewVerticalTabGroupCommandChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the NewVerticalTabGroupCommand property.
        /// </summary>
        protected virtual void OnNewVerticalTabGroupCommandChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        private bool CanExecuteNewVerticalTabGroupCommand(object parameter)
        {
            if (LayoutElement == null)
                return false;
            var parentDocumentGroup = LayoutElement.FindParent<LayoutDocumentPaneGroup>();
            var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane;
            return ((parentDocumentGroup == null ||
                parentDocumentGroup.ChildrenCount == 1 ||
                parentDocumentGroup.Root.Manager.AllowMixedOrientation || 
                parentDocumentGroup.Orientation == System.Windows.Controls.Orientation.Horizontal) &&
                parentDocumentPane != null &&
                parentDocumentPane.ChildrenCount > 1);
        }

        private void ExecuteNewVerticalTabGroupCommand(object parameter)
        {
            var layoutElement = LayoutElement;
            var parentDocumentGroup = layoutElement.FindParent<LayoutDocumentPaneGroup>();
            var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane;

            if (parentDocumentGroup == null)
            {
                var grandParent = parentDocumentPane.Parent as ILayoutContainer;
                parentDocumentGroup = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Horizontal };
                grandParent.ReplaceChild(parentDocumentPane, parentDocumentGroup);
                parentDocumentGroup.Children.Add(parentDocumentPane);
            }
            parentDocumentGroup.Orientation = System.Windows.Controls.Orientation.Horizontal; 
            int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane);
            parentDocumentGroup.InsertChildAt(indexOfParentPane + 1, new LayoutDocumentPane(layoutElement));
            layoutElement.IsActive = true;
            layoutElement.Root.CollectGarbage();
        }
        #endregion

        #region NewHorizontalTabGroupCommand

        /// <summary>
        /// NewHorizontalTabGroupCommand Dependency Property
        /// </summary>
        public static readonly DependencyProperty NewHorizontalTabGroupCommandProperty =
            DependencyProperty.Register("NewHorizontalTabGroupCommand", typeof(ICommand), typeof(LayoutItem),
                new FrameworkPropertyMetadata((ICommand)null,
                    new PropertyChangedCallback(OnNewHorizontalTabGroupCommandChanged)));

        /// <summary>
        /// Gets or sets the NewHorizontalTabGroupCommand property.  This dependency property 
        /// indicates the new horizontal tab group command.
        /// </summary>
        public ICommand NewHorizontalTabGroupCommand
        {
            get { return (ICommand)GetValue(NewHorizontalTabGroupCommandProperty); }
            set { SetValue(NewHorizontalTabGroupCommandProperty, value); }
        }

        /// <summary>
        /// Handles changes to the NewHorizontalTabGroupCommand property.
        /// </summary>
        private static void OnNewHorizontalTabGroupCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnNewHorizontalTabGroupCommandChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the NewHorizontalTabGroupCommand property.
        /// </summary>
        protected virtual void OnNewHorizontalTabGroupCommandChanged(DependencyPropertyChangedEventArgs e)
        {
        }


        private bool CanExecuteNewHorizontalTabGroupCommand(object parameter)
        {
            if (LayoutElement == null)
                return false;
            var parentDocumentGroup = LayoutElement.FindParent<LayoutDocumentPaneGroup>();
            var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane;
            return ((parentDocumentGroup == null ||
                parentDocumentGroup.ChildrenCount == 1 ||
                parentDocumentGroup.Root.Manager.AllowMixedOrientation ||
                parentDocumentGroup.Orientation == System.Windows.Controls.Orientation.Vertical) &&
                parentDocumentPane != null &&
                parentDocumentPane.ChildrenCount > 1);
        }

        private void ExecuteNewHorizontalTabGroupCommand(object parameter)
        {
            var layoutElement = LayoutElement;
            var parentDocumentGroup = layoutElement.FindParent<LayoutDocumentPaneGroup>();
            var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane;

            if (parentDocumentGroup == null)
            {
                var grandParent = parentDocumentPane.Parent as ILayoutContainer;
                parentDocumentGroup = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical };
                grandParent.ReplaceChild(parentDocumentPane, parentDocumentGroup);
                parentDocumentGroup.Children.Add(parentDocumentPane);
            }
            parentDocumentGroup.Orientation = System.Windows.Controls.Orientation.Vertical;
            int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane);
            parentDocumentGroup.InsertChildAt(indexOfParentPane + 1, new LayoutDocumentPane(layoutElement));
            layoutElement.IsActive = true;
            layoutElement.Root.CollectGarbage();
        }       
        #endregion

        #region MoveToNextTabGroupCommand

        /// <summary>
        /// MoveToNextTabGroupCommand Dependency Property
        /// </summary>
        public static readonly DependencyProperty MoveToNextTabGroupCommandProperty =
            DependencyProperty.Register("MoveToNextTabGroupCommand", typeof(ICommand), typeof(LayoutItem),
                new FrameworkPropertyMetadata((ICommand)null,
                    new PropertyChangedCallback(OnMoveToNextTabGroupCommandChanged)));

        /// <summary>
        /// Gets or sets the MoveToNextTabGroupCommand property.  This dependency property 
        /// indicates move to next tab group command.
        /// </summary>
        public ICommand MoveToNextTabGroupCommand
        {
            get { return (ICommand)GetValue(MoveToNextTabGroupCommandProperty); }
            set { SetValue(MoveToNextTabGroupCommandProperty, value); }
        }

        /// <summary>
        /// Handles changes to the MoveToNextTabGroupCommand property.
        /// </summary>
        private static void OnMoveToNextTabGroupCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnMoveToNextTabGroupCommandChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the MoveToNextTabGroupCommand property.
        /// </summary>
        protected virtual void OnMoveToNextTabGroupCommandChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        private bool CanExecuteMoveToNextTabGroupCommand(object parameter)
        {
            if (LayoutElement == null)
                return false;

            var parentDocumentGroup = LayoutElement.FindParent<LayoutDocumentPaneGroup>();
            var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane;
            return (parentDocumentGroup != null &&
                parentDocumentPane != null &&
                parentDocumentGroup.ChildrenCount > 1 &&
                parentDocumentGroup.IndexOfChild(parentDocumentPane) < parentDocumentGroup.ChildrenCount - 1 &&
                parentDocumentGroup.Children[parentDocumentGroup.IndexOfChild(parentDocumentPane) + 1] is LayoutDocumentPane);
        }

        private void ExecuteMoveToNextTabGroupCommand(object parameter)
        {
            var layoutElement = LayoutElement;
            var parentDocumentGroup = layoutElement.FindParent<LayoutDocumentPaneGroup>();
            var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane;
            int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane);
            var nextDocumentPane = parentDocumentGroup.Children[indexOfParentPane + 1] as LayoutDocumentPane;
            nextDocumentPane.InsertChildAt(0, layoutElement);
            layoutElement.IsActive = true;
            layoutElement.Root.CollectGarbage();
        }

        #endregion

        #region MoveToPreviousTabGroupCommand

        /// <summary>
        /// MoveToPreviousTabGroupCommand Dependency Property
        /// </summary>
        public static readonly DependencyProperty MoveToPreviousTabGroupCommandProperty =
            DependencyProperty.Register("MoveToPreviousTabGroupCommand", typeof(ICommand), typeof(LayoutItem),
                new FrameworkPropertyMetadata((ICommand)null,
                    new PropertyChangedCallback(OnMoveToPreviousTabGroupCommandChanged)));

        /// <summary>
        /// Gets or sets the MoveToPreviousTabGroupCommand property.  This dependency property 
        /// indicates move to rpevious tab group command.
        /// </summary>
        public ICommand MoveToPreviousTabGroupCommand
        {
            get { return (ICommand)GetValue(MoveToPreviousTabGroupCommandProperty); }
            set { SetValue(MoveToPreviousTabGroupCommandProperty, value); }
        }

        /// <summary>
        /// Handles changes to the MoveToPreviousTabGroupCommand property.
        /// </summary>
        private static void OnMoveToPreviousTabGroupCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((LayoutItem)d).OnMoveToPreviousTabGroupCommandChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the MoveToPreviousTabGroupCommand property.
        /// </summary>
        protected virtual void OnMoveToPreviousTabGroupCommandChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        private bool CanExecuteMoveToPreviousTabGroupCommand(object parameter)
        {
            if (LayoutElement == null)
                return false;
            var parentDocumentGroup = LayoutElement.FindParent<LayoutDocumentPaneGroup>();
            var parentDocumentPane = LayoutElement.Parent as LayoutDocumentPane;
            return (parentDocumentGroup != null &&
                parentDocumentPane != null &&
                parentDocumentGroup.ChildrenCount > 1 &&
                parentDocumentGroup.IndexOfChild(parentDocumentPane) > 0 &&
                parentDocumentGroup.Children[parentDocumentGroup.IndexOfChild(parentDocumentPane) - 1] is LayoutDocumentPane);
        }

        private void ExecuteMoveToPreviousTabGroupCommand(object parameter)
        {
            var layoutElement = LayoutElement;
            var parentDocumentGroup = layoutElement.FindParent<LayoutDocumentPaneGroup>();
            var parentDocumentPane = layoutElement.Parent as LayoutDocumentPane;
            int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane);
            var nextDocumentPane = parentDocumentGroup.Children[indexOfParentPane - 1] as LayoutDocumentPane;
            nextDocumentPane.InsertChildAt(0, layoutElement);
            layoutElement.IsActive = true;
            layoutElement.Root.CollectGarbage();
        }
        #endregion



    }
}
