//----------------------------------------------------------------------------
// SuperLabel.cs
//
// Custom C1Report field: SuperLabel
//
// Copyright (C) ComponentOne LLC
//----------------------------------------------------------------------------

#if !(CLR40 || CLR45)
#error This code requires .NET 4.0 or newer.
#endif
#define DYNAMIC_ASMS // undefine this and add a reference to C1.Win.C1SuperTooltip.4 assembly to use static reference

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.ComponentModel;
using System.IO;

using C1.C1Preview;

namespace C1.C1Report.CustomFields
{
    /// <summary>
    /// Inherits from <see cref="Field"/> and uses an instance of
    /// <b>C1.Win.C1SuperTooltip.C1SuperLabel</b> component to draw HTML content.
    /// </summary>
#if GRAPECITY
    [Description("スーパーラベル")]
#else
    [Description("SuperLabel")]
#endif
    public class SuperLabel : C1.C1Report.Field
    {
#if DYNAMIC_ASMS
        private dynamic _slbl = null;
#else
        private C1.Win.C1SuperTooltip.C1SuperLabel _slbl = null;
#endif

        /// <summary>
        /// Initializes a new instance of the <see cref="SuperLabel"/> class.
        /// </summary>
        public SuperLabel()
        {
#if DYNAMIC_ASMS
            _slbl = DynLoader.CreateC1SuperLabel();
#else
            _slbl = new C1.Win.C1SuperTooltip.C1SuperLabel();
#endif
            //
            PictureAlign = PictureAlignEnum.Clip;
        }

        /// <summary>
        /// Renders HTML content using the <b>C1SuperLabel</b> component.
        /// </summary>
        /// <param name="value">Field text.</param>
        /// <param name="img">Field image.</param>
        /// <param name="designTime">Whether we in design time or runtime.</param>
        override protected void GetRenderContent(ref string value, ref Image img, bool designTime)
        {
            // create image
            using (Bitmap bmp = new Bitmap(1, 1))
            using (Graphics g = Graphics.FromImage(bmp))
            {
                // calculate field size in pixels 
                // (based on field size in twips and screen resolution)
                Size size = GetFieldSizePixels(g);
                Rectangle rc = new Rectangle(Point.Empty, size);
                PointF dpi = new PointF(g.DpiX, g.DpiY);

                _slbl.Text = value; // show bound value instead of text (this.Text)
                _slbl.Font = this.Font;
                _slbl.BackColor = Utils.FromWpfColor(this.BackColor);
                _slbl.ForeColor = Utils.FromWpfColor(this.ForeColor);
                _slbl.Width = rc.Width;
                // handle CanGrow/CanShrink (TFS~~18920).
                if (!designTime && (CanGrow || CanShrink))
                {
                    var h = _slbl.Measure(rc.Width).Height;
                    if ((CanGrow && h > rc.Height) || (CanShrink && h < rc.Height))
                        _slbl.Height = rc.Height = h;
                    else
                        _slbl.Height = rc.Height;
                }
                else
                    _slbl.Height = rc.Height;

                // create metafile image (this is the return value)
                IntPtr hdc = g.GetHdc();
                try
                {
                    Metafile m = new Metafile(hdc, rc, MetafileFrameUnit.Pixel, this.ParentReport.EmfType);
                    using (Graphics meta = Graphics.FromImage(m))
                    {
                        meta.PageUnit = GraphicsUnit.Pixel;
                        _slbl.DrawToGraphics(meta, rc);
                    }
                    // Following code added as workaround for Windows bug.
                    // Windows processes EmfOnly metafiles incorrectly when
                    // large fonts used in system and new Windows7 scaling mode selected.
                    using (MemoryStream ms2 = new MemoryStream())
                    {
                        GraphicsUtils.WriteMetafileToStream(m, ms2);
                        ms2.Seek(0, SeekOrigin.Begin);
                        using (Metafile m2 = (Metafile)Image.FromStream(ms2))
                        {
                            if (m.Width != m2.Width || m.Height != m2.Height)
                            {
                                // fix required
                                Size szFixed = new Size(Utils.Round(m2.Width / GraphicsUtils.ScreenDpiX * m2.HorizontalResolution),
                                    Utils.Round(m2.Height / GraphicsUtils.ScreenDpiY * m2.VerticalResolution));
                                Metafile m3 = new Metafile(hdc, new Rectangle(Point.Empty, szFixed), MetafileFrameUnit.Pixel, this.ParentReport.EmfType);
                                using (Graphics g3 = Graphics.FromImage(m3))
                                    g3.DrawImage(m2, 0, 0, szFixed.Width, szFixed.Height);
                                MemoryStream ms3 = new MemoryStream();
                                GraphicsUtils.WriteMetafileToStream(m3, ms3);
                                ms3.Seek(0, SeekOrigin.Begin);
                                img = Image.FromStream(ms3);
                                m.Dispose();
                            }
                            else
                            {
                                img = m;
                            }
                        }
                    }
                }
                finally
                {
                    // done with reference dc
                    g.ReleaseHdc(hdc);
                }
            }
        }

        private Size GetFieldSizePixels(Graphics g)
        {
            Size sz = new Size((int)(Width / 1440f * g.DpiX), (int)(Height / 1440f * g.DpiY));

            // can't be empty
            if (sz.Width <= 0) sz.Width = 1;
            if (sz.Height <= 0) sz.Height = 1;

            // return size
            return sz;
        }
    }
}
