using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.ComponentModel;
using System.Drawing.Design;
using System.Drawing.Html;
using System.Drawing;
using System.Globalization;

namespace System.Windows.Forms
{
  // ml: added click event args
  public class UrlClickEventArgs : EventArgs
  {
    public string URL {get; set; }
    public bool Processed { get; set; }

    public UrlClickEventArgs(string url)
    {
      URL = url;
      Processed = false;
    }
  }
  
  public class HtmlPanel
        : ScrollableControl
    {
        #region Fields
        protected InitialContainer _htmlContainer;

        #endregion

        #region Ctor

        /// <summary>
        /// Creates a new HtmlPanel
        /// </summary>
        public HtmlPanel()
        {
            _htmlContainer = new InitialContainer();

            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.Opaque, true);
            //SetStyle(ControlStyles.Selectable, true);

            DoubleBuffered = true;

            BackColor = SystemColors.Window;
            AutoScroll = true;

            HtmlRenderer.AddReference(Assembly.GetCallingAssembly());
        }

        #endregion

        #region Properties

        [DesignerSerializationVisibility( DesignerSerializationVisibility.Visible)]
        public override bool AutoSize
        {
            get
            {
                return base.AutoSize;
            }
            set
            {
                base.AutoSize = value;
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override bool AutoScroll
        {
            get
            {
                return base.AutoScroll;
            }
            set
            {
                base.AutoScroll = value;
            }
        }

        /// <summary>
        /// Gets the Initial HtmlContainer of this HtmlPanel
        /// </summary>
        public InitialContainer HtmlContainer
        {
            get { return _htmlContainer; }
        }

        /// <summary>
        /// Gets or sets the text of this panel
        /// </summary>
        [Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor)), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Localizable(true), Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                base.Text = value;

                CreateFragment();
                MeasureBounds();
                Invalidate();
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Creates the fragment of HTML that is rendered
        /// </summary>
        protected virtual void CreateFragment()
        {
          // ml: added culture neutral number conversion.
          // Number conversion must be done culture neutral.
          CultureInfo cultureInfo = new CultureInfo("en-US");
          string fontSize = Font.Size.ToString(cultureInfo);

          string font = string.Format("font: {0}pt {1}; ", fontSize, Font.FontFamily.Name);
          string padding = string.Format("padding: {0}px {1}px {2}px {3}px; ", Padding.Top, Padding.Right, Padding.Bottom, Padding.Left);

          // ml: use an html block element with fewest side effects. Let the caller define the space around the text.
          _htmlContainer = new InitialContainer("<div style=\"" + font + padding + "\">" + Text + "</div>");
        }

        /// <summary>
        /// Measures the bounds of the container
        /// </summary>
        public virtual void MeasureBounds()
        {
          // ml: we need the entire client area for all types of HTML controls.
          _htmlContainer.SetBounds(ClientRectangle);
          //_htmlContainer.SetBounds(this is HtmlLabel ? new Rectangle(0, 0, 10, 10) : ClientRectangle);

          using (Graphics g = CreateGraphics())
          {
              _htmlContainer.MeasureBounds(g);
          }
            
          AutoScrollMinSize = Size.Round(_htmlContainer.MaximumSize);
        }

        protected override void OnClick(EventArgs e)
        {
            base.OnClick(e);

            Focus();
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            MeasureBounds();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            if (!(this is  HtmlLabel)) e.Graphics.Clear(SystemColors.Window);

            
            _htmlContainer.ScrollOffset = AutoScrollPosition;
            e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            _htmlContainer.Paint(e.Graphics);

        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            foreach (CssBox box in _htmlContainer.LinkRegions.Keys)
            {
                RectangleF rect = _htmlContainer.LinkRegions[box];
                if (Rectangle.Round(rect).Contains(e.X, e.Y))
                {
                    Cursor = Cursors.Hand;
                    return;
                }
            }

            Cursor = Cursors.Default;
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);

            foreach (CssBox box in _htmlContainer.LinkRegions.Keys)
            {
                RectangleF rect = _htmlContainer.LinkRegions[box];
                if (Rectangle.Round(rect).Contains(e.X, e.Y))
                {
                  // ml: added support for click event.
                  string url = box.GetAttribute("href", string.Empty);
                  if (!OnUrlClicked(url))
                    CssValue.GoLink(url);
                  return;
                }
            }

        }

        #endregion

        #region Events
      
      // ml: support for URL click event.
        public event EventHandler<UrlClickEventArgs> UrlClicked;
        private bool OnUrlClicked(string url)
        {
          if (UrlClicked != null)
          {
            UrlClickEventArgs args = new UrlClickEventArgs(url);
            UrlClicked(this, args);
            return args.Processed;
          }
          return false;
        }
        #endregion

    }
}
