using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Threading;

namespace Ricciolo.Controls
{
    public class AdvancedListBox : ListBox
    {

        internal static readonly DependencyPropertyKey IsLosingSelectionPropertyKey;
        internal static readonly DependencyPropertyKey IsGettingSelectionPropertyKey;
        internal static readonly DependencyPropertyKey SelectionDirectionPropertyKey;
        internal static readonly DependencyProperty IsLosingSelectionProperty;
        internal static readonly DependencyProperty IsGettingSelectionProperty;
        internal static readonly DependencyProperty SelectionDirectionProperty;
        private DependencyObject removeUiItem;
        private DependencyObject addUiItem;

        static AdvancedListBox()
        {
            IsLosingSelectionPropertyKey = DependencyProperty.RegisterReadOnly("IsLosingSelection", typeof(Boolean), typeof(AdvancedListBox), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
            IsGettingSelectionPropertyKey = DependencyProperty.RegisterReadOnly("IsGettingSelection", typeof(Boolean), typeof(AdvancedListBox), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
            SelectionDirectionPropertyKey = DependencyProperty.RegisterReadOnly("SelectionDirection", typeof(SelectionDirection), typeof(AdvancedListBox), new FrameworkPropertyMetadata(SelectionDirection.None, FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
            IsLosingSelectionProperty = IsLosingSelectionPropertyKey.DependencyProperty;
            IsGettingSelectionProperty = IsGettingSelectionPropertyKey.DependencyProperty;
            SelectionDirectionProperty = SelectionDirectionPropertyKey.DependencyProperty;

            DefaultStyleKeyProperty.OverrideMetadata(typeof(AdvancedListBox), new FrameworkPropertyMetadata(typeof(AdvancedListBox)));
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            return new ListBoxItem();
        }

        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return (item is ListBoxItem);
        }

        protected override void OnSelectionChanged(SelectionChangedEventArgs e)
        {
            if (removeUiItem != null)
            {
                removeUiItem.ClearValue(IsLosingSelectionPropertyKey);
                removeUiItem.ClearValue(IsGettingSelectionPropertyKey);
                removeUiItem.ClearValue(IsGettingSelectionPropertyKey);
                removeUiItem = null;
            }

            if (addUiItem != null)
            {
                addUiItem.ClearValue(IsLosingSelectionPropertyKey);
                addUiItem.ClearValue(IsGettingSelectionPropertyKey);
                addUiItem.ClearValue(IsGettingSelectionPropertyKey);
                addUiItem = null;
            }

            int removeIndex = -1;
            int addIndex = -1;
            if (e.RemovedItems.Count > 0)
            {
                removeIndex = this.Items.IndexOf(e.RemovedItems[0]);
                removeUiItem = this.ItemContainerGenerator.ContainerFromItem(e.RemovedItems[0]);
                removeUiItem.SetValue(IsLosingSelectionPropertyKey, true);
                removeUiItem.SetValue(IsGettingSelectionPropertyKey, false);
            }

            if (e.AddedItems.Count > 0)
            {
                addIndex = this.Items.IndexOf(e.AddedItems[0]);
                addUiItem = this.ItemContainerGenerator.ContainerFromItem(e.AddedItems[0]);
                addUiItem.SetValue(IsGettingSelectionPropertyKey, true);
                addUiItem.SetValue(IsLosingSelectionPropertyKey, false);
            }

            SelectionDirection direction = SelectionDirection.None;
            if (addIndex > removeIndex && removeIndex >= 0)
                direction = SelectionDirection.Down;
            else if (addIndex < removeIndex && removeIndex >= 0)
                direction = SelectionDirection.Up;
            if (removeUiItem != null)
                removeUiItem.SetValue(SelectionDirectionPropertyKey, direction);
            if (addUiItem != null)
                addUiItem.SetValue(SelectionDirectionPropertyKey, direction);

            base.OnSelectionChanged(e);
        }

        internal void NotifyAdvancedListBoxItemMouseUp(AdvancedListBoxItem advancedListBoxItem)
        {
            object item = base.ItemContainerGenerator.ItemFromContainer(advancedListBoxItem);
            if (item != null)
            {
                base.SelectedItem = advancedListBoxItem;
            }
        }

    }

    public enum SelectionDirection
    {
        None,
        Up,
        Down
    }
}

