/* G.E.M
 * - Jeffrey M. Barber
 * - mathsex.com
 * - kddresearch.org
 * (c) 2005, to the above
 * 
 * This Source Code is Closed unless you work for
 *   Jeffrey Michael Barber
 *   William Henry Hsu
 * 
 * Do not distribute unless you or the person you
 * plan to give it to apply to the above restriction
 * 
 */
package gem.gui.render;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import gem.gui.render.controls.ControlInterface;
import gem.gui.tools.RenderContext;

/**
 * @author Jeffrey M. Barber
 */
public class EdgeRender
{
    public static final int EdgeStyle_Solid             = 0;
    public static final int EdgeStyle_Dotted            = 1;
    public static final int EdgeStyle_Dash              = 2;
    public static final int EdgeStyle_Bold              = 3;
    public static final int EdgeStyle_BoldDot           = 4;
    public static final int EdgeStyle_BoldDash          = 5;
    public static final int EdgeDirectedEndStyle_Arrow  = 0;
    public static final int EdgeDirectedEndStyle_Bubble = 1;

    public static void RenderArrow(RenderContext RC, Point Src, Point Dest,
            double A, double B)
    {
        double DX = Src.x - Dest.x;
        double DY = Src.y - Dest.y;
        double L = Math.sqrt(DX * DX + DY * DY);
        DX /= L;
        DY /= L;
        double NX = (DX * A - DY * B) + Dest.x;
        double NY = (DX * B + DY * A) + Dest.y;
        double NX2 = (DX * A + DY * B) + Dest.x;
        double NY2 = (-DX * B + DY * A) + Dest.y;
        int[] pnts = new int[]
        { Dest.x, Dest.y, (int) NX, (int) NY, (int) NX2, (int) NY2 };
        RC.gc.fillPolygon(pnts);
        RC.gc.drawPolygon(pnts);
    }

    public static void RenderBubble(RenderContext RC, Point Src, Point Dest,
            double A, double B)
    {
        double DX = Src.x - Dest.x;
        double DY = Src.y - Dest.y;
        double L = Math.sqrt(DX * DX + DY * DY);
        DX /= L;
        DY /= L;
        double SX = -A / 2;
        double SY = -A / 2;
        //if(DX > 0 && DY > 0 ) { SX *= -1; SY *= -1; }
        //		else if(DX > 0 && DY < 0 ) { SX *= -1; SY *= -1; }
        //		else if(DX < 0 && DY > 0 ) SX *= -1;
        double NX = (DX * A) / 2 + Dest.x + SX;
        double NY = (DY * A) / 2 + Dest.y + SY;
        RC.gc.fillOval((int) NX, (int) NY, (int) A, (int) A);
        RC.gc.drawOval((int) NX, (int) NY, (int) A, (int) A);
        /*
         * int[] pnts = new int[] {Dest.x, Dest.y, (int)NX, (int)NY, (int)NX2,
         * (int)NY2}; RC.gc.fillPolygon(pnts); RC.gc.drawPolygon(pnts);
         */
    }

    public static void RenderEdge(RenderContext RC, EdgeInstance EI)
    {
        if(EI.Definition.Style == EdgeStyle_Solid)
        {
            RC.gc.setLineStyle(SWT.LINE_SOLID);
            RC.gc.setLineWidth(1);
        } else if(EI.Definition.Style == EdgeStyle_Dotted)
        {
            RC.gc.setLineStyle(SWT.LINE_DOT);
            RC.gc.setLineWidth(1);
        } else if(EI.Definition.Style == EdgeStyle_Dash)
        {
            RC.gc.setLineStyle(SWT.LINE_DASH);
            RC.gc.setLineWidth(1);
        } else if(EI.Definition.Style == EdgeStyle_Bold)
        {
            RC.gc.setLineStyle(SWT.LINE_SOLID);
            RC.gc.setLineWidth(3);
        } else if(EI.Definition.Style == EdgeStyle_BoldDot)
        {
            RC.gc.setLineStyle(SWT.LINE_DOT);
            RC.gc.setLineWidth(3);
        } else if(EI.Definition.Style == EdgeStyle_BoldDash)
        {
            RC.gc.setLineStyle(SWT.LINE_DASH);
            RC.gc.setLineWidth(3);
        }
        int SourceX = RC.transform.tx(EI.From.X);
        int SourceY = RC.transform.ty(EI.From.Y);
        if(EI.From == EI.To)
        {
            Point Src = new Point(SourceX + 10000, SourceY);
            Point Dest = new Point(SourceX, SourceY);
            Dest = EI.To.GetExternLink(Src, Dest);
            RC.gc.drawOval(Dest.x, Dest.y - 30, 60, 60);
            Src = new Point(SourceX + 5000, SourceY + 10000);
            RC.gc.setBackground(RC.constants.Colors._EdgeHeadColor);
            if(EI.Definition.Directed)
            {
                if(EI.Definition.EndPointStyle == EdgeDirectedEndStyle_Arrow)
                {
                    RenderArrow(RC, Src, Dest, EI.Definition.EndProfileA,
                            EI.Definition.EndProfileB);
                } else if(EI.Definition.EndPointStyle == EdgeDirectedEndStyle_Bubble)
                {
                    RenderBubble(RC, Src, Dest, EI.Definition.EndProfileA,
                            EI.Definition.EndProfileB);
                }
            }
            RC.gc.setForeground(RC.constants.Colors._DefaultText);
            RC.gc.setFont(RC.constants.Fonts.EditorFont);
            for(int k = 0; k < EI.PropertyInstances.size(); k++)
            {
                ControlInterface CI = (ControlInterface) EI.PropertyInstances
                        .get(k);
                CI.Render(RC, EI.From.X
                        + RC.transform.is(Dest.x - SourceX + 60), EI.From.Y);
            }
            RC.gc.setLineStyle(SWT.LINE_SOLID);
            RC.gc.setLineWidth(1);
            return;
        } else
        {
            int DestX = RC.transform.tx(EI.To.X);
            int DestY = RC.transform.ty(EI.To.Y);
            RC.gc.setForeground(EI.Definition.EdgeColor);
            Point Src = new Point(SourceX, SourceY);
            Point Dest = new Point(DestX, DestY);
            Dest = EI.To.GetExternLink(Src, Dest);
            Src = EI.From.GetExternLink(Dest, Src);
            RC.gc.drawLine(Src.x, Src.y, Dest.x, Dest.y);
            RC.gc.setBackground(RC.constants.Colors._EdgeHeadColor);
            if(EI.Definition.Directed)
            {
                if(EI.Definition.EndPointStyle == EdgeDirectedEndStyle_Arrow)
                {
                    RenderArrow(RC, Src, Dest, EI.Definition.EndProfileA,
                            EI.Definition.EndProfileB);
                } else if(EI.Definition.EndPointStyle == EdgeDirectedEndStyle_Bubble)
                {
                    RenderBubble(RC, Src, Dest, EI.Definition.EndProfileA,
                            EI.Definition.EndProfileB);
                }
            }
            RC.gc.setForeground(RC.constants.Colors._DefaultText);
            RC.gc.setFont(RC.constants.Fonts.EditorFont);
            for(int k = 0; k < EI.PropertyInstances.size(); k++)
            {
                ControlInterface CI = (ControlInterface) EI.PropertyInstances
                        .get(k);
                CI.Render(RC, (EI.From.X + EI.To.X) / 2.0,
                        (EI.From.Y + EI.To.Y) / 2.0);
            }
            RC.gc.setLineStyle(SWT.LINE_SOLID);
            RC.gc.setLineWidth(1);
        }
    }
}