using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using C1.Silverlight;

namespace StockPortfolio
{
    public partial class SearchSymbol : UserControl
    {
        private bool _updating = false;
        private string _text = string.Empty;
        private string _symbol = string.Empty;
        private int _maxItems = 9;
        private Dictionary<string, string> _items = new Dictionary<string, string>();

        public SearchSymbol()
        {
            InitializeComponent();
        }

        #region ** object model

        public bool DropDownOpensUp
        {
            get 
            { 
                return (searchSymbols.DropDownDirection == DropDownDirection.ForceAbove);
            }
            set 
            {
                if (value)
                {
                    searchSymbols.DropDownDirection = DropDownDirection.ForceAbove;
                }
                else 
                {
                    searchSymbols.DropDownDirection = DropDownDirection.ForceBelow;
                }
            }
        }

        public Dictionary<string, string> Items
        {
            get { return _items; }
            set { _items = value; }
        }
        public string Text
        {
            get { return _text; }
        }

        public string Symbol
        {
            get { return _symbol; }
        }

        public event EventHandler SelectionChange;

        #endregion

        private void txtSymbol_TextChanged(object sender, TextChangedEventArgs e)
        {
            if ((!_updating) && (_selectedText != txtSymbol.Text))
            {
                string text = txtSymbol.Text;
                List<string> items = BuildList(text);
                if (items.Count == 0)
                {
                    searchSymbols.IsDropDownOpen = false;
                }
                else
                {
                    listBox.Items.Clear();
                    foreach (string key in items)
                    {
                        listBox.Items.Add(BuildItem(text, key, _items[key]));
                    }
                    searchSymbols.IsDropDownOpen = true;
                }
            }
        }

        private void txtSymbol_KeyDown(object sender, KeyEventArgs e)
        {
            int delta = 0;
            switch (e.Key)
            {
                case Key.Down:
                    delta = 1;
                    break;

                case Key.Up:
                    delta = -1;
                    break;

                case Key.Enter:
                    CommitListSelection();
                    break;

                case Key.Escape:
                    searchSymbols.IsDropDownOpen = false;
                    break;
            }

            int oldIndex;
            if ((_selectedItem != null) && listBox.Items.Contains(_selectedItem))
            {                
                oldIndex = listBox.Items.IndexOf(_selectedItem);
            }
            else
            {
                oldIndex = (DropDownOpensUp ? listBox.Items.Count : -1);
            }
            int index = Math.Min(Math.Max(0, oldIndex + delta), listBox.Items.Count - 1);
            if ((index>=0) && (index < listBox.Items.Count))
            {
                SelectedItem = listBox.Items[index] as ContentControl;
            }
        }

        private void txtSymbol_LostFocus(object sender, RoutedEventArgs e)
        {
            searchSymbols.IsDropDownOpen = false;
        }

        private string _selectedText;
        void li_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            SelectedItem = sender as ContentControl;
            if (SelectedItem != null)
            {
                CommitListSelection();
            }
        }

        #region ** private stuff

        // commit listbox selection

        private ContentControl _selectedItem = null;
        private ContentControl SelectedItem 
        {
            get 
            {
                return _selectedItem;
            }
            set 
            {
                if (_selectedItem != null) 
                {
                    (_selectedItem.Content as StackPanel).Background = new SolidColorBrush(Colors.Transparent);
                }
                _selectedItem = value;
                if (value != null) 
                {
                    (value.Content as StackPanel).Background = new SolidColorBrush(Color.FromArgb(0xff, 0xb8, 0xd1, 0xe4));
                }
            }
        }

        private void CommitListSelection()
        {
            StackPanel sp = (StackPanel)(_selectedItem).Content;
            if (sp != null)
            {
                // apply text to textbox, hide popup
                _updating = true;
                _symbol = (sp.Children[0] as TextBlock).Text;
                _text = (sp.Children[1] as TextBlock).Text;
                txtSymbol.Text = _symbol;
                _updating = false;

                // fire event to indicate a choice was made
                CommitSelection();

                searchSymbols.IsDropDownOpen = false;

                _selectedText = txtSymbol.Text;
                txtSymbol.Select(0, txtSymbol.Text.Length);
            }
        }

        // commit C1TextBox change
        private void CommitSelection()
        {
            if (SelectionChange != null)
            {
                SelectionChange(this, new EventArgs());
            }
        }

        // methods used for building the pick list
        private List<string> BuildList(string text)
        {
            List<string> list = new List<string>();
            if (text.Length > 0)
            {
                // add matches on symbol first
                foreach (string key in _items.Keys)
                {
                    if (key.StartsWith(text, StringComparison.InvariantCultureIgnoreCase))
                    {
                        list.Add(key);
                        if (list.Count >= _maxItems)
                            break;
                    }
                }

                // add matches on name second
                foreach (string key in _items.Keys)
                {
                    if (_items[key].IndexOf(text, StringComparison.InvariantCultureIgnoreCase) > -1 &&
                        !list.Contains(key))
                    {
                        list.Add(key);
                        if (list.Count >= _maxItems)
                            break;
                    }
                }
            }
            return list;
        }

        private FrameworkElement BuildItem(string search, string key, string text)
        {
            StackPanel p = new StackPanel();
            p.Orientation = Orientation.Horizontal;
            p.Background = new SolidColorBrush(Colors.Transparent);
            p.Children.Add(BuildSubItem(search, key, 60));
            p.Children.Add(BuildSubItem(search, text, 200));

            ContentControl c = new ContentControl();
            c.MouseLeftButtonDown += new MouseButtonEventHandler(li_MouseLeftButtonDown);
            c.Content = p;

            return c;
        }

        private TextBlock BuildSubItem(string search, string text, double width)
        {
            TextBlock tb = new TextBlock();
            tb.Text = string.Empty;

            for (int start = 0; ; )
            {
                // look for a match
                int index = text.IndexOf(search, start, StringComparison.InvariantCultureIgnoreCase);

                // match not found, add remainder and be done
                if (index < 0)
                {
                    CreateRun(tb, false, text.Substring(start));
                    break;
                }

                // match found: add regular and bold parts
                if (index > start)
                {
                    CreateRun(tb, false, text.Substring(start, index - start));
                }
                CreateRun(tb, true, text.Substring(index, search.Length));
                start = index + search.Length;
            }

            tb.Width = width;
            return tb;
        }

        private void CreateRun(TextBlock tb, bool highlight, string text)
        {
            Run run = new Run();
            run.Text = text;
            run.FontFamily = FontFamily;
            run.FontSize = FontSize;
            run.FontWeight = highlight ? FontWeights.Bold : FontWeights.Normal;
            tb.Inlines.Add(run);
        }

        #endregion

    }
}
