using System;
using System.Collections;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using C1.FlexMap;
using C1.Win.Map;

namespace C1.Win.FlexReport.CustomFields.Maps
{
    /// <summary>
    /// A helper class used to draw a map legend.
    /// </summary>
    internal class MapperLegend
    {
        private Win.Map.MapLegend _c1Legend;

        /// <summary>
        /// Defaults.
        /// </summary>
        private static class Constants
        {
            public const float BorderThickness = 1;
            public static readonly Color BorderColor = Color.LightSlateGray;
            public const int Margin = 12;
        }

        public MapperLegend(Win.Map.MapLegend c1Legend)
        {
            Debug.Assert(c1Legend != null);
            _c1Legend = c1Legend;

            c1Legend.Alignment = ContentAlignment.TopRight;
            c1Legend.Margin = new Padding(Constants.Margin);
            
            // border
            c1Legend.Style.Border.Left.Color = Constants.BorderColor;
            c1Legend.Style.Border.Left.Width = Constants.BorderThickness;
            c1Legend.Style.Border.Top.Color = Constants.BorderColor;
            c1Legend.Style.Border.Top.Width = Constants.BorderThickness;
            c1Legend.Style.Border.Right.Color = Constants.BorderColor;
            c1Legend.Style.Border.Right.Width = Constants.BorderThickness;
            c1Legend.Style.Border.Bottom.Color = Constants.BorderColor;
            c1Legend.Style.Border.Bottom.Width = Constants.BorderThickness;
        }

        public void UpdateFromOwner(IMapperOwner owner, Legend mapLegend)
        {
            if(_c1Legend!=null)
                _c1Legend.Items.Clear();
            
            if (owner == null || mapLegend == null || _c1Legend == null)
                return;

            // Orientation:
            _c1Legend.Layout = mapLegend.Orientation == Orientation.Vertical
                ? MapLegendLayout.TallTable
                : MapLegendLayout.WideTable;

            // alignment:
            _c1Legend.Alignment = mapLegend.LegendAlignment;
            
            // margins
            _c1Legend.Margin = mapLegend.Margin;
            _c1Legend.Padding = mapLegend.Padding;

            // borders
            _c1Legend.Style.Border.Left.Width = mapLegend.BorderThickness.Left;
            _c1Legend.Style.Border.Top.Width = mapLegend.BorderThickness.Top;
            _c1Legend.Style.Border.Right.Width = mapLegend.BorderThickness.Right;
            _c1Legend.Style.Border.Bottom.Width = mapLegend.BorderThickness.Bottom;
            
            //
            _c1Legend.Style.BackColor = mapLegend.BackColor;

            // title
            _c1Legend.Title.Position = mapLegend.Orientation == Orientation.Vertical
                ? DockStyle.Top
                : DockStyle.Left;
            _c1Legend.Title.Caption = mapLegend.Caption;
            ApplyItemStyle(_c1Legend.Title.Style, null, mapLegend);
            _c1Legend.Title.Style.Alignment = ContentAlignment.MiddleCenter;

            Action<IEnumerable> addItems = (items) =>
                {
                    foreach (ILegendItem li in items)
                    {
                        if (li.LegendItemVisible)
                        {
                            var item = MakeItem(li, mapLegend, owner);
                            if (item != null)
                                _c1Legend.Items.Add(item);
                        }
                    }
                };

            if (mapLegend.Automatic)
                addItems(mapLegend.Owner.Layers);
            else
                addItems(mapLegend.Items);
        }

        private Win.Map.MapLegendItem MakeItem(ILegendItem legendItem, Legend legend, IMapperOwner owner)
        {
            if (legendItem.LegendItemKind == LegendItemKind.KML
                || legendItem.LegendItemKind == LegendItemKind.None)
                return null;

            var item = new Win.Map.MapLegendItem();
            item.Label = legendItem.LegendItemCaption;
            ApplyItemStyle(item.Style, legendItem, legend);

            switch (legendItem.LegendItemKind)
            {
                case LegendItemKind.Point:
                    item.Kind = MapLegendItemKind.Marker;
                    item.Shape = (FlexMap.MarkerShape)legendItem.LegendItemMarkerShape;
                    var markerSize = (float)legendItem.LegendItemMarkerSize;
                    if (markerSize < 0) markerSize = item.Style.Font.Height / 3f;
                    item.Size = Util.GetMarkerSize(legendItem.LegendItemMarkerShape, markerSize);
                    break;
                case LegendItemKind.Line:
                    item.Kind = MapLegendItemKind.Line;
                    var lineSize = item.Style.Font.Height * 3f;
                    item.Size = new SizeF(lineSize, lineSize);
                    break;
                case LegendItemKind.ColorSwatch:
                    item.Kind = MapLegendItemKind.Rectangle;
                    var swatchSize = item.Style.Font.Height;
                    item.Size = Util.GetMarkerSize(MarkerShape.Square, swatchSize);
                    break;
                case LegendItemKind.Text:
                    item.Kind = MapLegendItemKind.None;
                    break;
                case LegendItemKind.KML:
                case LegendItemKind.None:
                    System.Diagnostics.Debug.Assert(false, "should not going here.");
                    return null;
                default:
                    System.Diagnostics.Debug.Assert(false, "unknown legend item type");
                    return null;
            }

            return item;
        }

        #region Style handlers
        private System.Drawing.Color GetTextColor(Legend legend, ILegendItem legendItem)
        {
            if (legendItem != null && !Util.IsColorEmpty(legendItem.LegendItemTextColor))
                return legendItem.LegendItemTextColor;
            else
                return legend.TextColor;
        }

        private System.Drawing.Font GetFont(Legend legend, ILegendItem legendItem)
        {
            if (legendItem != null)
                return legendItem.LegendItemFont;
            else
                return legend.Font;
        }

        private System.Drawing.Color GetStrokeColor(Legend legend, ILegendItem legendItem)
        {
            if (legendItem != null)
                return legendItem.LegendItemStrokeColor;
            else
                return System.Drawing.Color.Black;
        }
        #endregion

        private void ApplyItemStyle(Style style, ILegendItem mapperItem, Legend mapLegend)
        {
            style.ForeColor = GetTextColor(mapLegend, mapperItem);
            var font = GetFont(mapLegend, mapperItem);
            if (font != null) style.Font = font;
            style.Alignment = ContentAlignment.MiddleLeft;
            style.Stroke.Color = GetStrokeColor(mapLegend, mapperItem);

            if (mapperItem != null)
            {
                style.BackColor = mapperItem.LegendItemFillColor;
                style.Stroke.Style = (C1.Win.Map.DashStyle) mapperItem.LegendItemDashStyle;

                if (mapperItem.LegendItemLineThickness >= 0)
                    style.Stroke.Width = (float) mapperItem.LegendItemLineThickness;
            }
        }
    }
}
