using System;
using System.Collections;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace VCommon.Logging.Viewer.Utility
{
    internal static class ListViewExtensions
    {
        // ReSharper disable InconsistentNaming
        // ReSharper disable UnusedMember.Local
        private const int HDI_WIDTH = 0x0001;

        private const int HDI_HEIGHT = HDI_WIDTH;
        private const int HDI_TEXT = 0x0002;
        private const int HDI_FORMAT = 0x0004;
        private const int HDI_LPARAM = 0x0008;
        private const int HDI_BITMAP = 0x0010;
        private const int HDI_IMAGE = 0x0020;
        private const int HDI_DI_SETITEM = 0x0040;
        private const int HDI_ORDER = 0x0080;
        private const int HDI_FILTER = 0x0100;

        private const int HDF_LEFT = 0x0000;
        private const int HDF_RIGHT = 0x0001;
        private const int HDF_CENTER = 0x0002;
        private const int HDF_JUSTIFYMASK = 0x0003;
        private const int HDF_RTLREADING = 0x0004;
        private const int HDF_OWNERDRAW = 0x8000;
        private const int HDF_STRING = 0x4000;
        private const int HDF_BITMAP = 0x2000;
        private const int HDF_BITMAP_ON_RIGHT = 0x1000;
        private const int HDF_IMAGE = 0x0800;
        private const int HDF_SORTUP = 0x0400;
        private const int HDF_SORTDOWN = 0x0200;

        private const int LVM_FIRST = 0x1000; // List messages
        private const int LVM_GETHEADER = LVM_FIRST + 31;
        private const int HDM_FIRST = 0x1200; // Header messages
        private const int HDM_SETIMAGELIST = HDM_FIRST + 8;
        private const int HDM_GETIMAGELIST = HDM_FIRST + 9;
        private const int HDM_GETITEM = HDM_FIRST + 11;
        private const int HDM_SETITEM = HDM_FIRST + 12;
        // ReSharper restore UnusedMember.Local
        // ReSharper restore InconsistentNaming

        [DllImport("user32.dll", EntryPoint = "SendMessage")]
        private static extern IntPtr SendMessageLVCOLUMN(IntPtr hWnd, int msg, IntPtr wParam, ref Lvcolumn lPlvcolumn);

        //This method used to set arrow icon
        public static void SetSortIcon(this ListView listView, int columnIndex, SortOrder order)
        {
            var columnHeader = NativeMethods.SendMessage(listView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);

            for (var columnNumber = 0; columnNumber <= listView.Columns.Count - 1; columnNumber++)
            {
                var columnPtr = new IntPtr(columnNumber);
                var lvColumn = new Lvcolumn { mask = HDI_FORMAT };

                SendMessageLVCOLUMN(columnHeader, HDM_GETITEM, columnPtr, ref lvColumn);

                if (order != SortOrder.None && columnNumber == columnIndex)
                {
                    switch (order)
                    {
                        case SortOrder.Ascending:
                            lvColumn.fmt &= ~HDF_SORTDOWN;
                            lvColumn.fmt |= HDF_SORTUP;
                            break;

                        case SortOrder.Descending:
                            lvColumn.fmt &= ~HDF_SORTUP;
                            lvColumn.fmt |= HDF_SORTDOWN;
                            break;
                    }
                    lvColumn.fmt |= HDF_LEFT | HDF_BITMAP_ON_RIGHT;
                }
                else
                {
                    lvColumn.fmt &= ~HDF_SORTDOWN & ~HDF_SORTUP & ~HDF_BITMAP_ON_RIGHT;
                }

                SendMessageLVCOLUMN(columnHeader, HDM_SETITEM, columnPtr, ref lvColumn);
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct Lvcolumn
        {
            public int mask;
            private readonly int cx;

            [MarshalAs(UnmanagedType.LPTStr)]
            private readonly string pszText;

            private readonly IntPtr hbm;
            private readonly int cchTextMax;
            public int fmt;
            private readonly int iSubItem;
            private readonly int iImage;
            private readonly int iOrder;
        }
    }
    public class ColumnSorter : IComparer
    {
        private readonly Comparer _listViewItemComparer;

        public ColumnSorter()
        {
            SortColumn = 0;

            Order = SortOrder.None;

            _listViewItemComparer = new Comparer(CultureInfo.CurrentUICulture);
        }

        public int SortColumn { set; get; }

        public SortOrder Order { set; get; }

        public int Compare(object x, object y)
        {
            try
            {
                var lviX = (ListViewItem)x;
                var lviY = (ListViewItem)y;

                int compareResult;

                if (lviX.SubItems[SortColumn].Tag != null && lviY.SubItems[SortColumn].Tag != null)
                {
                    compareResult = _listViewItemComparer.Compare(lviX.SubItems[SortColumn].Tag,
                        lviY.SubItems[SortColumn].Tag);
                }
                else
                {
                    compareResult = _listViewItemComparer.Compare(lviX.SubItems[SortColumn].Text,
                        lviY.SubItems[SortColumn].Text);
                }

                if (Order == SortOrder.Ascending)
                {
                    return compareResult;
                }
                if (Order == SortOrder.Descending)
                {
                    return -compareResult;
                }
                return 0;
            }
            catch
            {
                return 0;
            }
        }
    }
}