// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using OpenLiveWriter.Localization.Bidi;

namespace OpenLiveWriter.Controls
{
    public class ImageComboBox : ComboBox
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private Container components = null;

        public ImageComboBox(Size imageSize)
        {
            DropDownStyle = ComboBoxStyle.DropDownList;
            DrawMode = DrawMode.OwnerDrawFixed;
            ItemHeight = CalculateItemHeight(imageSize);
        }

        public bool AllowMirroring
        {
            get
            {
                return _allowMirroring;
            }
            set
            {
                _allowMirroring = value;
            }
        }

        private bool _allowMirroring = true;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            // screen invalid drawing states
            if (DesignMode || e.Index == -1)
                return;

            // get item text and image
            string itemText = Items[e.Index].ToString();
            IComboItem comboItem = (IComboItem)Items[e.Index];
            Image itemImage = comboItem.Image;

            // determine state
            bool selected = (e.State & DrawItemState.Selected) > 0;

            // calculate colors
            Color backColor, textColor;
            if (selected && Focused)
            {
                textColor = SystemColors.ControlText;
                backColor = Color.FromArgb(50, SystemColors.Highlight);
            }
            else
            {
                backColor = SystemColors.Window;
                textColor = SystemColors.ControlText;
            }
            Rectangle area = e.Bounds;
            //overlap issue in RTL builds in the selected box area ONLY
            if (area.X == 21)
            {
                area = ClientRectangle;
            }
            BidiGraphics g = new BidiGraphics(e.Graphics, area);

            // draw background (always paint white over it first)
            g.FillRectangle(Brushes.White, area);
            using (SolidBrush solidBrush = new SolidBrush(backColor))
                g.FillRectangle(solidBrush, area);

            // draw icon
            g.DrawImage(AllowMirroring, itemImage, area.Left + IMAGE_INSET, area.Top + area.Height / 2 - itemImage.Height / 2);

            // text format and drawing metrics
            TextFormatFlags ellipsesStringFormat = TextFormatFlags.VerticalCenter |
                   TextFormatFlags.WordBreak | TextFormatFlags.ExpandTabs | TextFormatFlags.WordEllipsis;
            int leftMargin = IMAGE_INSET + itemImage.Width + TEXT_INSET;

            // draw title line
            // post title
            int titleWidth = area.Right - leftMargin;
            Rectangle titleRectangle = new Rectangle(area.Left + leftMargin, area.Top, titleWidth, area.Height);
            g.DrawText(
                itemText,
                e.Font, titleRectangle, textColor, ellipsesStringFormat);

            // separator line if necessary
            if (!selected && DroppedDown)
            {
                using (Pen pen = new Pen(SystemColors.ControlLight))
                    g.DrawLine(pen, area.Left, area.Bottom - 1, area.Right, area.Bottom - 1);
            }

            // focus rectange if necessary
            e.DrawFocusRectangle();
        }

        private int CalculateItemHeight(Size imageSize)
        {
            float fontHeight = Font.GetHeight();
            return TOP_INSET +                                  // top-margin
                Math.Max(Convert.ToInt32(fontHeight), imageSize.Height) + // contentHeight
                BOTTOM_INSET;                                   // air at bottom
        }

        // item metrics
        private const int TOP_INSET = 2;
        private const int BOTTOM_INSET = 2;
        private const int IMAGE_INSET = 3;
        private const int TEXT_INSET = 5;

        public interface IComboItem
        {
            Image Image { get; }
        }
    }
}