using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;

namespace Azyobuzi.Twirunrun
{
    public class StatusesListView : ListView
    {
        public StatusesListView()
        {
            this.DoubleBuffered = true;
            this.View = View.Details;
            this.VirtualMode = true;
            this.HeaderStyle = ColumnHeaderStyle.None;
            this.FullRowSelect = true;
            this.CacheVirtualItems += this_CacheVirtualItems;
            this.RetrieveVirtualItem += this_RetrieveVirtualItem;
            this.Columns.Add("名前", Settings.Instance.NameWidth);
            this.Columns.Add("投稿");
            this.Invalidated += (sender, e) => this.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.ColumnContent);
            this.OwnerDraw = true;
            this.DrawSubItem += this_DrawSubItem;
        }

        private int oldCount;

        private IList<StatusInfo> statuses;
        public IList<StatusInfo> Statuses
        {
            set
            {
                if (statuses != null) oldCount = statuses.Count;
                statuses = value;
                SetItemsCount();
            }
            get
            {
                return statuses;
            }
        }

        public void SetItemsCount(int count, int addCount)
        {
            this.Invoke((MethodInvoker)(() =>
            {
                VirtualListSize = count;
                this.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.ColumnContent);

                if (addCount != 0)
                {
                    var indexes = this.SelectedIndices.Cast<int>().ToArray();
                    this.SelectedIndices.Clear();
                    indexes.Select(oldIndex => oldIndex +
                        (int)Settings.Instance.OrderType.SelectCase()
                            .Case(SortOrder.Ascending, () => -1)
                            .Case(SortOrder.Descending, () => +1)
                            .Default(() => 0)
                            .Result
                        )
                        .ForEach(newIndex => this.SelectedIndices.Add(newIndex));
                }
            }));
        }

        public void SetItemsCount()
        {
            SetItemsCount(Statuses.Count, statuses.Count - oldCount);
        }

        protected override void OnSelectedIndexChanged(EventArgs e)
        {
            base.OnSelectedIndexChanged(e);
        }

        private ListViewItem CreateListViewItem(StatusInfo item)
        {
            var s = Settings.Instance;

            var lvi = new ListViewItem();
            lvi.BackColor = item.Type == StatusTypes.Retweet ? s.RetweetedBgColor : s.MainBgColor;
            lvi.Font = s.MainFont;
            lvi.ForeColor = item.Type == StatusTypes.Retweet ? s.RetweetedFontColor : s.MainFontColor;
            lvi.Text = s.NameType == NameTypes.Name ? item.User.Name : item.User.Identifier.ScreenName;
            lvi.Tag = item;

            lvi.SubItems.Add(item.Text.Replace('\n', ' '));

            return lvi;
        }

        Dictionary<int, ListViewItem> itemcache = new Dictionary<int, ListViewItem>();

        private void this_CacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
        {
            itemcache.Clear();
            Enumerable.Range(e.StartIndex, e.EndIndex - e.StartIndex)
                .Select(index => Tuple.Create(index, CreateListViewItem(Statuses[index])))
                .ForEach(_ => itemcache.Add(_.Item1, _.Item2));
        }

        private void this_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
        {
            ListViewItem item = null;
            bool result = itemcache.TryGetValue(e.ItemIndex, out item);
            if (!result) item = CreateListViewItem(Statuses[e.ItemIndex]);
            e.Item = item;
        }

        private void this_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
        {
            if (e.ItemIndex < 0 || e.ColumnIndex < 0) return;

            e.Graphics.InterpolationMode = InterpolationMode.High;

            using (var b = new SolidBrush(
                (e.ItemState & ListViewItemStates.Selected) == ListViewItemStates.Selected ?
                    SystemColors.Highlight : e.SubItem.BackColor))
            {
                e.Graphics.FillRectangle(b, e.Bounds);
            }

            var foreColor = (e.ItemState & ListViewItemStates.Selected) == ListViewItemStates.Selected ?
                SystemColors.HighlightText : e.Item.ForeColor;

            e.ColumnIndex.SelectCase()
                .Case(0, () =>//名前部
                {
                    const int LEFT_SPACE = 2;
                    var itemPoint = e.Bounds.Location;
                    //アイコン描画
                    var iconUri = ((StatusInfo)e.Item.Tag).ProfileImageUri;
                    int iconsize = e.Bounds.Height - 1;
                    var icon = Icons.GetItem(iconUri);
                    if (icon == null)
                    {
                        Icons.AddAsync(iconUri);
                    }
                    else
                    {
                        e.Graphics.DrawImage(icon, itemPoint.X + LEFT_SPACE, itemPoint.Y, iconsize, iconsize);
                    }
                    //名前描画
                    TextRenderer.DrawText(e.Graphics,
                        e.SubItem.Text,
                        e.SubItem.Font,
                        new Rectangle(
                            itemPoint.X + LEFT_SPACE + iconsize + LEFT_SPACE,
                            itemPoint.Y,
                            e.Bounds.Width - LEFT_SPACE - iconsize - LEFT_SPACE,
                            e.Bounds.Height
                        ),
                        foreColor,
                        TextFormatFlags.NoPrefix |
                        TextFormatFlags.VerticalCenter |
                        TextFormatFlags.EndEllipsis |
                        TextFormatFlags.SingleLine
                    );
                })
                .Case(1, () =>//投稿内容部
                {
                    TextRenderer.DrawText(e.Graphics,
                        e.SubItem.Text,
                        e.SubItem.Font,
                        e.Bounds,
                        foreColor,
                        TextFormatFlags.NoPrefix |
                        TextFormatFlags.VerticalCenter |
                        TextFormatFlags.WordEllipsis |
                        TextFormatFlags.SingleLine);
                });
        }

        public StatusInfo[] GetSelectedStatuses()
        {
            return this.SelectedIndices.Cast<int>().Select(index => Statuses[index]).ToArray();
        }

        public StatusInfo GetSelectedStatus()
        {
            return GetSelectedStatuses().FirstOrDefault();
        }
    }
}
