using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using ChaKi.Entity.Corpora;
using ChaKi.Entity.Corpora.Annotations;
using System.Runtime.InteropServices;
using ChaKi.Common;
using ChaKi.Common.Settings;
using ChaKi.Entity.Settings;

namespace DependencyEditSLA.Widgets
{
    class DepArrow
    {
        [DllImport("gdi32.dll")]
        static extern bool PtInRegion(IntPtr hrgn, int X, int Y);

        static DepArrow()
        {
            m_RegionPen = new Pen(Color.Gray, 12);
            m_RegionPen.SetLineCap(LineCap.RoundAnchor, LineCap.RoundAnchor, DashCap.Flat);

            m_Brush[0] = new SolidBrush(Color.Gray);
            m_Brush[1] = new SolidBrush(Color.Red);
            m_Brush[2] = new SolidBrush(Color.Black);
            m_Brush[3] = new SolidBrush(Color.DarkOrange);

            m_Font = new Font("Arial", 10, FontStyle.Italic);
        }

        public DepArrow(Link _link, int id, int _from, int _to, Rectangle _fromBox, Rectangle _toBox)
        {
            this.Visible = true;
            this.Index = id;
            this.FromIndex = _from;
            this.ToIndex = _to;
            this.IsSelected = false;
            this.IsCrossing = false;
            this.Link = _link;
            this.Tag = _link.Tag.Name;

            // ラベル（コントロール）を作成
            m_TagLabel = new LinkTagLabel(_link);

            m_Region = new Region();

            // デフォルト（Diagonal Mode）の描画位置をセーブ
            RecalcLayout(_fromBox, _toBox);
        }

        public virtual void RecalcLayout(Rectangle fromBox, Rectangle toBox)
        {
            m_FromBox = fromBox;
            m_ToBox = toBox;
            this.StartPnt = new Point(fromBox.Left, fromBox.Bottom);
            this.EndPnt = new Point(toBox.Left, toBox.Bottom);

        }

        public bool Visible { get; set; }
        public Point StartPnt { get; set; }
        public Point EndPnt { get; set; }
        public Point EndPnt2 { get; set; }
        public int FromIndex { get; set; }
        public int ToIndex { get; set; }
        public int Index { get; set; }
        public Link Link { get; set; }
        public string Tag { get; set; }
        public bool IsSelected { get; set; }
        public bool IsCrossing { get; set; }
        public Region Rgn
        {
            get { return m_Region; }
        }
        public LinkTagLabel TagLabel
        {
            get { return m_TagLabel; }
        }


        public virtual void Draw(Graphics g, bool bDraft, Point offset)
        {
            if (!this.Visible)
            {
                return;
            }

            Pen srcPen = LinkPens.Find(this.Tag);
            Pen pen = (Pen)srcPen.Clone();
            if (IsSelected) pen.Color = Color.Red;
            if (IsCrossing) pen.Color = Color.DarkOrange;
            if (this.Tag == "P")
            {   // "P"はNon-directedなのでLinecapなし. TODO: 名称ではなくIsDirectedによる判定が必要
                pen.SetLineCap(LineCap.Square, LineCap.Square, DashCap.Flat);
            }

            DrawParams dp = new DrawParams(this.StartPnt, this.EndPnt, this.EndPnt2, bDraft, offset);

            // HitTest領域を求めて保存しておく
            if (true/*typeid(*pDC) != typeid(CMetaFileDC)*/)
            {
                GraphicsPath gp = new GraphicsPath();
                gp.AddLines(new Point[] { dp.ps, dp.pm, dp.pe });
                gp.Widen(m_RegionPen);

                if (m_Region != null)
                {
                    m_Region.Dispose();
                    m_Region = new Region(gp);
                }
            }
            //本来の描画処理
            if (!DepEditSettings.Current.ReverseDepArrowDirection)
            {
                g.DrawLines(pen, new Point[] { dp.ps, dp.pm, dp.pe });
            }
            else
            {
                g.DrawLines(pen, new Point[] { dp.pe, dp.pm, dp.ps });
            }

            // タグラベルの更新処理
            if (!bDraft)
            {
                this.TagLabel.Location = dp.tagLocation;
                this.TagLabel.Text = this.Tag;
            }

            pen.Dispose();
        }

        public virtual DAHitType HitTest(Graphics g, Point point)
        {
            if (m_Region == null)
            {
                return DAHitType.None;
            }
            // Hit at other neighbouring area?
            try
            {
                if (PtInRegion(m_Region.GetHrgn(g), point.X, point.Y))
                {
                    return DAHitType.Other;
                }
            }
            catch
            {
                Console.WriteLine("Error!");
                m_Region = null;
            }
            return DAHitType.None;
        }

        public virtual void MoveHeadTo(Point point)
        {
            this.EndPnt = point;
        }

        protected Rectangle m_FromBox;
        protected Rectangle m_ToBox;
        protected Region m_Region;  // 矢印のヒットエリア全体を表す領域オブジェクト
        protected Point m_TagLocation;  // タグ文字列の左上位置
        protected LinkTagLabel m_TagLabel;

        static protected Pen m_RegionPen;
        static protected Brush[] m_Brush = new Brush[4];
        static protected Font m_Font;

    }

    class DrawParams
    {
        public DrawParams(Point _s, Point _e, Point _e2, bool bDraft, Point offset)
        {
            isReverse = (_s.X > _e.X);
            ps = new Point(_s.X, _s.Y);
            if (!isReverse)
            {
                ps = new Point(_s.X + 8, _s.Y);
                if (bDraft)
                {
                    pe = _e;
                }
                else
                {
                    pe = new Point(_e.X - 2, _e.Y - 16);
                }
                pm = new Point(ps.X, pe.Y);
            }
            else
            {
                ps = new Point(_s.X, _s.Y - 8);
                if (bDraft)
                {
                    pe = _e;
                }
                else
                {
                    pe = new Point(_e.X + 16, _e.Y);
                }
                pm = new Point(pe.X, ps.Y);
            }
            tagLocation = pm;

            ps.Offset(offset);
            pe.Offset(offset);
            pm.Offset(offset);
            tagLocation.Offset(offset);
        }

        public Point ps;
        public Point pe;
        public Point pm;
        public Point tagLocation;
        public bool isReverse;
    }
}
