using System;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace DevComponents.AdvTree
{
	namespace Display
	{
		/// 
		/// Base class for drawing node connectors.
		/// 
		public abstract class NodeConnectorDisplay
		{
			//private bool m_RootNode=false;
			//private bool m_DrawRootAllLevels=false;
			//private bool m_EndCap=true;
			//private bool m_DrawConnectorUnderNodes=true;
			/// 
			/// Creates new instance of the object.
			/// 
			public NodeConnectorDisplay()
			{
			}
			/// 
			/// Draws connector line between two nodes.
			/// 
			/// Connector context information.
			public virtual void DrawConnector(ConnectorRendererEventArgs info){}
            ///// 
            ///// Returns the connector starting coordinates.
            ///// 
            ///// Connector display information.
            ///// Point object.
            //protected virtual Point GetStartPoint(ConnectorRendererEventArgs info)
            //{
            //    Point p=Point.Empty;
            //    if(info.IsRootNode)
            //    {
            //        //int toMidPoint=info.ToNode.Bounds.Top+info.ToNode.Bounds.Height/2;
            //        //if(info.FromNode.Bounds.Top>toMidPoint)
            //        if(IsAbove(info.FromNode,info.ToNode))
            //            p=new Point(info.FromNode.BoundsRelative.Left+info.FromNode.BoundsRelative.Width/2,info.FromNode.BoundsRelative.Top);
            //            //else if(info.FromNode.Bounds.Bottom
            ///// Returns true if fromNode is above the toNode.
            ///// 
            ///// From Node object.
            ///// To Node object
            ///// True if fromNode is above toNode.
            //protected bool IsAbove(Node fromNode, Node toNode)
            //{
            //    //int toMidPoint=toNode.Bounds.Top+toNode.Bounds.Height/2;
            //    //if(fromNode.Bounds.Top>toMidPoint)
            //    if(fromNode.BoundsRelative.Top>toNode.BoundsRelative.Bottom)
            //        return true;
            //    return false;
            //}
            ///// 
            ///// Returns true if fromNode is below toNode.
            ///// 
            ///// From Node object.
            ///// To Node object.
            ///// True if fromNode is below toNode.
            //protected bool IsBelow(Node fromNode, Node toNode)
            //{
            //    int toMidPoint=toNode.BoundsRelative.Top+toNode.BoundsRelative.Height/2;
            //    if(fromNode.BoundsRelative.Bottom
            ///// Returns whether connector is extended to underline the node.
            ///// 
            ///// Refernce to Node style.
            ///// True if node should be underlined by connector.
            //protected bool UnderlineNode(ElementStyle nodeStyle)
            //{
            //    if(!nodeStyle.PaintBottomBorder && !nodeStyle.PaintTopBorder &&
            //       !nodeStyle.PaintLeftBorder && !nodeStyle.PaintRightBorder)
            //        return true;
            //    return false;
            //}
            ///// 
            ///// Returns the connector end point. The array of end points. Two valid points will be returned if node needs to be underlined by connector.
            ///// 
            ///// Connector display info.
            ///// Array of point objects.
            //protected Point[] GetEndPoint(ConnectorRendererEventArgs info)
            //{
            //    // If to element is to the right of the from node and has left border end point is the vertical mid-point
            //    // If to element is to the left of the from node and has right border end point is the vertical mid-point
            //    // If there is no border end point is text bottom
            //    // If this is link connector the end point is the middle bottom or top point of the node
            //    Point p=Point.Empty;
            //    Point pLineEnd=Point.Empty;
            //    int capWidthOffset = 0; // GetCapWidthOffset(info.NodeConnector.EndCap, info.NodeConnector.EndCapSize);
            //    bool leftSide=this.IsOnLeftSide(info.FromNode,info.ToNode);
            //    if(info.LinkConnector && info.FromNode.BoundsRelative.Top>info.ToNode.BoundsRelative.Bottom)
            //        p=new Point(info.ToNode.BoundsRelative.X+info.ToNode.BoundsRelative.Width/2+(leftSide?capWidthOffset:-capWidthOffset),info.ToNode.BoundsRelative.Bottom+1);
            //    else if(info.LinkConnector && info.FromNode.BoundsRelative.Bottom
            ///// Returns the offest for the node connector cap.
            ///// 
            ///// Cap type.
            ///// Cap size.
            ///// 
            //protected int GetCapWidthOffset(eConnectorCap cap,Size size)
            //{
            //    int capWidthOffset=0;
            //    switch(cap)
            //    {
            //        case eConnectorCap.Arrow:
            //            capWidthOffset=size.Width+1;
            //            break;
            //        case eConnectorCap.Ellipse:
            //            capWidthOffset=size.Width;
            //            break;
            //    }
            //    return capWidthOffset;
            //}
            ///// 
            ///// Returns true if source node is on the left side of the target node.
            ///// 
            ///// Reference to source node.
            ///// Reference to target node.
            ///// True if source is on the left side of target.
            //protected bool IsOnLeftSide(Node source, Node target)
            //{
            //    if((source.BoundsRelative.Left+source.BoundsRelative.Width/2)>target.BoundsRelative.Left)
            //        return true;
            //    return false;
            //}
			/// 
			/// Returns new instance of pen object for node connector line. Caller is responsible for
			/// disposing of this object.
			/// 
			/// Node connector display info.
			/// New instance of Pen object.
			protected Pen GetLinePen(ConnectorRendererEventArgs info)
			{
                Pen pen = new Pen(info.NodeConnector.LineColor, info.NodeConnector.LineWidth);
                pen.DashStyle = info.NodeConnector.DashStyle;
                return pen;
			}
            ///// 
            ///// Returns new instance of pen object for the end node connector line. Caller is responsible for
            ///// disposing of this object.
            ///// 
            ///// Node connector display info.
            ///// New instance of Pen object.
            //protected Pen GetEndLinePen(ConnectorRendererEventArgs info)
            //{
            //    return new Pen(info.NodeConnector.LineColor,EndLineWidth);
            //}
            ///// 
            ///// Returns new instance of pen object for the node underline line. Caller is responsible for
            ///// disposing of this object.
            ///// 
            ///// Node connector display info.
            ///// New instance of Pen object.
            //protected Pen GetEndUnderlinePen(ConnectorRendererEventArgs info)
            //{
            //    return new Pen(info.NodeConnector.LineColor,EndLineWidth);
            //}
            //private int EndLineWidth
            //{
            //    get {return 1;}
            //}
//            /// 
//            /// Draws straight line connector between start and end point.
//            /// 
//            /// Node connector display info.
//            /// Start point.
//            /// End point.
//            /// Underline end point if any.
//            protected void DrawStraightLineConnector(ConnectorRendererEventArgs info, Point pStart, Point pEnd)
//            {
//                using (Pen pen = this.GetLinePen(info))
//                {
//                    if (pen.DashStyle != DashStyle.Solid)
//                    {
//                        SmoothingMode sm = info.Graphics.SmoothingMode;
//                        info.Graphics.SmoothingMode = SmoothingMode.Default;
//                        info.Graphics.DrawLine(pen, pStart, pEnd);
//                        info.Graphics.SmoothingMode = sm;
//                    }
//                    else
//                        info.Graphics.DrawLine(pen, pStart, pEnd);
//                }
//            }
//            /// 
//            /// Draws straight line connector between start and end point.
//            /// 
//            /// Node connector display info.
//            /// Start point.
//            /// End point.
//            /// Underline end point if any.
//            protected void DrawLineConnector(ConnectorRendererEventArgs info,Point pStart,Point pEnd, Point pEndUnderLine)
//            {
//                if(info.NodeConnector.LineWidth>1)
//                {
//                    // Merge lines nicely by filling and creating path...
//                    int rootLineWidth=this.EndLineWidth;
//                    int lineWidth=info.NodeConnector.LineWidth;
				
//                    using(Brush brush=GetLineBrush(info))
//                    {
//                        GraphicsPath path=GetConnectingPath(pStart,pEnd,lineWidth,rootLineWidth,info.IsRootNode,!(IsAbove(info.FromNode,info.ToNode) || IsBelow(info.FromNode,info.ToNode)));
//                        info.Graphics.FillPath(brush,path);
//                    }
//                }
//                else
//                {
//                    using(Pen pen=this.GetLinePen(info))
//                    {
//                        info.Graphics.DrawLine(pen,pStart,pEnd);
//                    }
//                }
//                if(!pEndUnderLine.IsEmpty)
//                {
//                    using(Pen pen=this.GetEndUnderlinePen(info))
//                    {
//                        info.Graphics.DrawLine(pen,pEnd,pEndUnderLine);
//                    }
//                }
//            }
//            private GraphicsPath GetConnectingPath(Point pStart, Point pEnd, int lineStartWidth, int lineEndWidth, bool bRoot, bool bRootSide)
//            {
//                int direction=1;
//                if(pStart.X>pEnd.X)
//                    direction=-1;
//                lineStartWidth++;
//                lineEndWidth++;
//                GraphicsPath path=new GraphicsPath();
//                if(bRoot && !bRootSide)
//                {
//                    path.AddLine(pStart.X,pStart.Y,pStart.X+lineStartWidth*direction,pStart.Y);
////					if(direction>0)
////						path.AddLine(pEnd.X+lineEndWidth*direction,pEnd.Y,pEnd.X,pEnd.Y);
////					else
////						path.AddLine(pEnd.X,pEnd.Y,pEnd.X+lineEndWidth*direction,pEnd.Y);
//                    if(direction>0)
//                    {
//                        path.AddLine(pStart.X+lineStartWidth*direction,pStart.Y, pEnd.X, pEnd.Y);
//                        path.AddLine(pEnd.X, pEnd.Y, pEnd.X, pEnd.Y + lineEndWidth*direction);
//                        path.AddLine(pEnd.X, pEnd.Y + lineEndWidth*direction, pStart.X, pStart.Y);
//                    }
//                    else
//                        path.AddLine(pEnd.X, pEnd.Y, pEnd.X, pEnd.Y + lineEndWidth*direction);
						
//                    path.CloseAllFigures();
////					if(Math.Abs(pEnd.Y-pStart.Y)<=8)
////						path.Widen(SystemPens.Highlight);
//                }
//                else
//                {
//                    int offsetStart=lineStartWidth/2;
//                    int offsetEnd=lineEndWidth/2;
//                    path.AddLine(pStart.X,pStart.Y-offsetStart,pStart.X,pStart.Y+offsetStart);
//                    path.AddLine(pEnd.X,pEnd.Y+offsetEnd,pEnd.X,pEnd.Y-offsetEnd);
//                    path.AddLine(pEnd.X,pEnd.Y-offsetEnd,pStart.X,pStart.Y-offsetStart);
//                    path.CloseAllFigures();
//                }
			
//                return path;
//            }
//            protected Brush GetLineBrush(ConnectorRendererEventArgs info)
//            {
//                return new SolidBrush(info.NodeConnector.LineColor);
//            }
//            protected void DrawEndLine(ConnectorRendererEventArgs info,Point pStart,Point pEnd,Point pEndUnderLine)
//            {
//                if(pEndUnderLine.IsEmpty)
//                {
//                    switch(info.NodeConnector.EndCap)
//                    {
//                        case eConnectorCap.Ellipse:
//                            {
//                                using(Pen pen=this.GetEndLinePen(info))
//                                {
//                                    Size endCapSize=info.NodeConnector.EndCapSize;
//                                    if(pStart.XpEnd.X)
//                                        direction=-1;
//                                    info.Graphics.DrawLine(pen,pEnd,new Point(pEnd.X+info.NodeConnector.EndCapSize.Width/3*direction,pEnd.Y));
//                                    Size endCapSize=info.NodeConnector.EndCapSize;
//                                    GraphicsPath arrow=GetArrowPath(endCapSize,pStart,pEnd);
//                                    info.Graphics.DrawPath(pen,arrow);
//                                }
//                                break;
//                            }
//                    }
//                }
//                else
//                {
//                    using(Pen pen=this.GetEndUnderlinePen(info))
//                    {
//                        info.Graphics.DrawLine(pen,pEnd,pEndUnderLine);
					
//                        // Connect underline to expand part
//                        if(NodeDisplay.DrawExpandPart(info.ToNode))
//                        {
//                            Rectangle re=NodeDisplay.GetNodeRectangle(eNodeRectanglePart.ExpandBounds,info.ToNode,info.Offset);
//                            Point p2=new Point((re.X>pEndUnderLine.X?re.X:re.Right)+(re.Width/2*(re.X>pEndUnderLine.X?1:-1)),re.Bottom);
//                            Point p1=new Point(p2.X,pEndUnderLine.Y+(pEndUnderLine.Y>p2.Y?(p2.Y-pEndUnderLine.Y)/2:-(p2.Y-pEndUnderLine.Y)/2));
//                            info.Graphics.DrawCurve(pen,new Point[]{pEndUnderLine,p1,p2},.5f);
//                        }
//                    }
//                }
//            }
//            private GraphicsPath GetArrowPath(Size capSize,Point pStart,Point pEnd)
//            {
//                GraphicsPath path=new GraphicsPath();
//                int direction=1;
//                if(pStart.X>pEnd.X)
//                    direction=-1;
			
//                pEnd.X+=(GetCapWidthOffset(eConnectorCap.Arrow,capSize)*direction);
//                path.AddLine(pEnd.X,pEnd.Y,pEnd.X-capSize.Width*direction,pEnd.Y-capSize.Height/2);
//                path.AddLine(pEnd.X-(2*capSize.Width/3*direction),pEnd.Y,pEnd.X-capSize.Width*direction,pEnd.Y+capSize.Height/2);
//                path.CloseAllFigures();
//                return path;
//            }
            //internal virtual ConnectorPointInfo GetConnectorPointInfo(ConnectorRendererEventArgs info, Point pStart, Point pEnd)
            //{
            //    ConnectorPointInfo pointInfo=new ConnectorPointInfo();
            //    int xMulti=1/*, yMulti=1*/;
            //    int lineWidth=info.NodeConnector.LineWidth;
            //    // used for direction control
            //    if(pStart.X>pEnd.X)
            //        xMulti=-1;
            //    //if(pStart.Y>pEnd.Y)
            //    //	yMulti=-1;
            //    if(info.ConnectorPoints!=null)
            //    {
            //        Point connPointsOffset=info.ToNode.BoundsRelative.Location;
            //        connPointsOffset.Offset(info.Offset.X,info.Offset.Y);
            //        GraphicsPath path=new GraphicsPath();
				
            //        pointInfo.Points1=new Point[info.ConnectorPoints.Count+2];
            //        pointInfo.Points1[0]=pStart;
            //        pointInfo.Points1[pointInfo.Points1.Length-1]=pEnd;
            //        if(lineWidth>1)
            //        {
            //            pointInfo.Points2=new Point[info.ConnectorPoints.Count+2];
            //            pointInfo.Points2[pointInfo.Points2.Length-1]=pStart;
            //            pointInfo.Points2[0]=pEnd;
            //            int i=pointInfo.Points1.Length-2;
            //            int k=1;
            //            foreach(Point pcp in info.ConnectorPoints)
            //            {
            //                pointInfo.Points1[i]=pcp;
            //                pointInfo.Points1[i].Offset(connPointsOffset.X,connPointsOffset.Y);
            //                pointInfo.Points2[k]=new Point(pcp.X+lineWidth*xMulti,pcp.Y);
            //                pointInfo.Points2[k].Offset(connPointsOffset.X,connPointsOffset.Y);
            //                k++;
            //                i--;
            //            }
            //        }
            //        else
            //        {
            //            int i=pointInfo.Points1.Length-2;
            //            foreach(Point pcp in info.ConnectorPoints)
            //            {
            //                pointInfo.Points1[i]=pcp;
            //                pointInfo.Points1[i].Offset(connPointsOffset.X,connPointsOffset.Y);
            //                i--;
            //            }
            //        }	
            //    }
            //    return pointInfo;
            //}
		}
	}
	/// 
	/// Represents custom connector path info.
	/// 
	internal class ConnectorPointInfo
	{
		public Point[] Points1=null;
		public Point[] Points2=null;
	}
}