/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package desenho.linhas;

import controlador.Diagrama;
import controlador.inspector.InspectorProperty;
import desenho.Elementar;
import desenho.FormaElementar;
import desenho.formas.Forma;
import desenho.preAnyDiagrama.PreTexto;
import diagramas.conceitual.Texto;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.HashMap;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 *
 * @author ccandido
 */
public class SuperLinha extends Linha {

    private static final long serialVersionUID = -6648325468968978514L;

    public SuperLinha(Diagrama master) {
        super(master);
    }
    private boolean inteligente = false;

    /**
     * *
     * Configura se a linha deverá mostrar os atributos de seta (inclusive para salvar em xml).
     */
    protected boolean showConfigSeta = true;

    public boolean isInteligente() {
        return inteligente;
    }

    public void setInteligente(boolean inteligente) {
        if (this.inteligente != inteligente) {
            this.inteligente = inteligente;
        }
    }

    public void SetInteligente(boolean inteligente) {
        boolean md = (this.inteligente != inteligente);
        setInteligente(inteligente);
        if (md && inteligente) {
            Clean();
        } 
    }

    public void Inicie(int maisQuantosPontos, Point pFim, Point pIni) {
        if (getPontos().isEmpty()) {
            PontoDeLinha pt1 = NovoPonto();
            pt1.setCentro(pFim);
            PontoDeLinha ant = pt1;

            for (int i = 0; i < maisQuantosPontos; i++) {
                ant = InserirPonto(ant);
                ant.IsTopOrBotton = false;
            }
            pt1 = InserirPonto(ant);
            pt1.IsTopOrBotton = true;
            pt1.setCentro(pIni);
        }
        //Inicie(local);
    }

    @Override
    public void ReciveClick(Elementar sender, boolean dbl, MouseEvent e) {
        if (dbl) {   //&& !isInteligente() inteligente não trata os pontos??????.
            if (sender instanceof PontoDeLinha) {
                PontoDeLinha pt = (PontoDeLinha) sender;
                if (pt.IsTopOrBotton) {
                    return;
                }
//                int i = getPontos().indexOf(pt) - 1;
//                int j = i + 2;
//                getPontos().get(i).Proximo = getPontos().get(j);

                RemoveSubItem(pt);
                reSetBounds();
            }
        }
    }

    @Override
    protected void ProcessaDblClick(MouseEvent e) {
        Point p = e.getPoint();
        for (int i = 1; i < getPontosParaDesenho().length; i++) {
            if (Linha.SegmentIntersectRectangle(p.x - 1, p.y - 1, p.x + 1, p.y + 1,
                    getPontosParaDesenho()[i - 1].x, getPontosParaDesenho()[i - 1].y,
                    getPontosParaDesenho()[i].x, getPontosParaDesenho()[i].y)) {
                PontoDeLinha pt = InserirPonto(i);
                pt.setCentro(p);
                //pt.IsHide = false;
                pt.setVisible(true);
                mouseExited(null);//evita que a linha permaneça na forma do mouseEntred.
                return;
            }
        }
    }
    
    public static final int distancia = 10; //usada também no comando do modelo.
    
    /**
     * Super método que organiza todo o sistema de desenho de linhas Estrutura (Posições):
     * <pre>
     *
     *          +----------+----------+----------+
     *          |          |          |          |
     *          |    G     |    H     |    I     |
     *          |          |          |          |
     *          +----------+----------+----------+
     *          |          |          |          |
     *          |    F     |    A     |    B     |
     *          |          |          |          |
     *          +----------+----------+----------+
     *          |          |          |          |
     *          |    E     |    D     |    C     |
     *          |          |          |          |
     *          +----------+----------+----------+
     *
     * </pre> Nota: parto do princípio de que sempre um dos elementos de uma ligação esta na posição A Em seguida, procuro (em relação a A) qual a posição do
     * segundo elemento.
     */
    @Override
    public synchronized void OrganizeLinha() {
        //??: TO-DO: continuaar correções como o feito em AD 0-1 e 2-1.
        if (!isInteligente()) {
            return;
        }

        Forma A = getFormaPontaA();
        Forma B = getFormaPontaB();

        if (A == null || B == null || (A.isSelecionado() && B.isSelecionado())) {
            return;
        }

        A = (Forma) A.ProcessaComposicao();
        B = (Forma) B.ProcessaComposicao();

        

        int ladoA = getPontaA().getLado();
        int ladoB = getPontaB().getLado();

        Point pontaA = getPontaA().getCentro();
        Point pontaB = getPontaB().getCentro();

        char letra;
        boolean inver = false;

        int ATop = A.getTop(); //melhora velociade
        int BTop = B.getTop();
        int ALeft = A.getLeft();
        int BLeft = B.getLeft();

        if (ALeft < BLeft) {
            if (ATop < BTop) {
                letra = 'C';
                if (A.getLeftWidth() >= BLeft) {
                    letra = 'D';
                } else if (A.getTopHeight() >= BTop) {
                    letra = 'B';
                }
            } else if (ATop > BTop) {
                letra = 'I';
                if (A.getLeftWidth() >= BLeft) {
                    letra = 'D';
                    inver = true;
                } else if (pontaA.y <= B.getTopHeight()) {
                    letra = 'B';
                }

            } else { // ==
                letra = 'B';
            }
        } else if (ALeft > BLeft) {
            if (ATop < BTop) {
                //letra = 'E';//Troca e inverte
                letra = 'I';
                inver = true;
                if (B.getLeftWidth() >= ALeft) {
                    letra = 'D';
                    inver = false;
                } else if (pontaA.y >= BTop) {
                    letra = 'B';
                    //inver = false;
                }
            } else if (ATop > BTop) {
                //letra = 'G';//Troca e inverte
                letra = 'C';
                inver = true;
                if (B.getLeftWidth() >= ALeft) {
                    letra = 'D';
                } else if (B.getTopHeight() >= ATop) {
                    letra = 'B';
                }

            } else { // ==
                //letra = 'F';
                letra = 'B';
                inver = true;
            }
        } else { // ==
            if (ATop > BTop) {
                //letra = 'H';
                letra = 'D';
                inver = true;
            } else if (ATop < BTop) {
                letra = 'D';
            } else { // ==
                letra = 'B'; //sobreposto
            }
        }

        if (inver) {
            B = getFormaPontaA();
            A = getFormaPontaB();

            A = (Forma) A.ProcessaComposicao();
            B = (Forma) B.ProcessaComposicao();

            ladoB = getPontaA().getLado();
            ladoA = getPontaB().getLado();

            pontaB = getPontaA().getCentro();
            pontaA = getPontaB().getCentro();

            ATop = A.getTop(); //melhora velociade
            BTop = B.getTop();
            ALeft = A.getLeft();
            BLeft = B.getLeft();
        }

        // <editor-fold defaultstate="collapsed" desc="Pontos para entornos">
        //Pontos para entorno de A
        Rectangle r = A.getBounds();
        r.grow(distancia, distancia);

        Point A1 = new Point(r.x, r.y);
        Point A0 = new Point(r.x, pontaA.y);
        Point A7 = new Point(r.x, r.y + r.height);
        Point A2 = new Point(pontaA.x, r.y);
        Point A6 = new Point(pontaA.x, r.y + r.height);
        Point A3 = new Point(r.x + r.width, r.y);
        Point A4 = new Point(r.x + r.width, pontaA.y);
        Point A5 = new Point(r.x + r.width, r.y + r.height);

        //Pontos para entorno de B
        r = B.getBounds();
        r.grow(distancia, distancia);

        Point B1 = new Point(r.x, r.y);
        Point B0 = new Point(r.x, pontaB.y);
        Point B7 = new Point(r.x, r.y + r.height);
        Point B2 = new Point(pontaB.x, r.y);
        Point B6 = new Point(pontaB.x, r.y + r.height);
        Point B3 = new Point(r.x + r.width, r.y);
        Point B4 = new Point(r.x + r.width, pontaB.y);
        Point B5 = new Point(r.x + r.width, r.y + r.height);
        //</editor-fold>

        // Calculo do centro.
        int tmp1 = (ALeft > BLeft) ? (BLeft + ALeft + B.getWidth()) / 2 : (BLeft + ALeft + A.getWidth()) / 2;
        int tmp2 = (ATop > BTop) ? (BTop + ATop + B.getHeight()) / 2 : (BTop + ATop + A.getHeight()) / 2;

        Point pc = new Point(tmp1, tmp2);

        Point tmpPoint = null;

        Point p1 = null, p2 = null, p3 = null, p4 = null;

        //A.SetTexto("A - " + letra);
        //B.SetTexto("B - " + letra);
        switch (letra) {
            // <editor-fold defaultstate="collapsed" desc="Case B">
            case 'B':
                switch (ladoA) {
                    case 0:
                        switch (ladoB) {
                            case 0:
                                p1 = A0;
                                if (pontoMaisProx(A0.y, A1.y, A7.y)) {
                                    if ((A1.y + distancia) < pontaB.y) {
                                        p2 = A1;
                                        p3 = new Point(pc.x, A1.y);
                                        p4 = new Point(pc.x, B0.y);
                                    } else {
                                        p2 = new Point(A0.x, B0.y);
                                    }
                                } else {
                                    if ((A7.y - distancia) > pontaB.y) {
                                        p2 = A7;
                                        p3 = new Point(pc.x, A7.y);
                                        p4 = new Point(pc.x, B0.y);
                                    } else {
                                        p2 = new Point(A7.x, B0.y);
                                    }
                                }
                                break;
                            case 1:
                                p1 = A0;
                                tmpPoint = menorPonto(A1, B2, false);
                                p2 = new Point(A1.x, tmpPoint.y);
                                p3 = new Point(B2.x, tmpPoint.y);
                                break;
                            case 2:
                                p1 = A0;
                                if (pontoMaisProx(A0.y, A1.y, A7.y)) {
                                    tmpPoint = menorPonto(A1, B3, false);
                                    p2 = new Point(A1.x, tmpPoint.y);
                                    p3 = new Point(B3.x, tmpPoint.y);
                                } else {
                                    tmpPoint = maiorPonto(A7, B5, false);
                                    p2 = new Point(A7.x, tmpPoint.y);
                                    p3 = new Point(B5.x, tmpPoint.y);
                                }
                                p4 = B4;
                                break;
                            case 3:
                                p1 = A0;
                                tmpPoint = maiorPonto(A7, B6, false);
                                p2 = new Point(A7.x, tmpPoint.y);
                                p3 = new Point(B6.x, tmpPoint.y);
                                break;
                        }
                        break;
                    case 1:
                        switch (ladoB) {
                            case 0:
                                if (pontaA.y - distancia < pontaB.y) {
                                    p1 = A2;
                                    p2 = new Point(pc.x, A2.y);
                                    p4 = new Point(pc.x, B0.y);
                                } else {
                                    p1 = new Point(A2.x, B0.y);
                                }
                                break;
                            case 1:
                                tmpPoint = menorPonto(A2, B2, false);
                                p1 = new Point(A2.x, tmpPoint.y);
                                p2 = new Point(B2.x, tmpPoint.y);
                                break;
                            case 2:
                                tmpPoint = menorPonto(A2, B3, false);

                                p1 = new Point(A2.x, tmpPoint.y);
                                p2 = new Point(B3.x, tmpPoint.y);

                                p3 = B4;
                                break;
                            case 3:
                                p1 = A2;
                                p2 = new Point(pc.x, A2.y);
                                p3 = new Point(pc.x, B6.y);
                                p4 = B6;

                                break;
                        }
                        break;
                    case 2:
                        switch (ladoB) {
                            case 0:
                                p1 = new Point(pc.x, A4.y);
                                p2 = new Point(pc.x, B0.y);
                                break;
                            case 1:
                                if (pontaB.y - distancia < pontaA.y) {
                                    p1 = new Point(pc.x, A4.y);
                                    p2 = new Point(pc.x, B2.y);
                                    p3 = B2;
                                } else {
                                    p1 = new Point(B2.x, A4.y);
                                }
                                break;
                            case 2:
                                p1 = new Point(pc.x, A4.y);
                                if (pontoMaisProx(B4.y, B3.y, B5.y)) {
                                    p2 = new Point(pc.x, B3.y);
                                    p3 = B3;
                                } else {
                                    p2 = new Point(pc.x, B5.y);
                                    p3 = B5;
                                }
                                p4 = B4;
                                break;
                            case 3:
                                if (pontaA.y > pontaB.y + distancia) {
                                    p1 = new Point(B6.x, A4.y);
                                } else {

                                    p1 = new Point(pc.x, A4.y);
                                    p2 = new Point(pc.x, B6.y);
                                    p3 = B6;
                                }
                                break;
                        }
                        break;
                    case 3:
                        switch (ladoB) {
                            case 0:
                                if (A6.y > pontaB.y) {
                                    p1 = A6;
                                    p2 = new Point(pc.x, A6.y);
                                    p3 = new Point(pc.x, B0.y);
                                } else {
                                    p1 = new Point(A6.x, B0.y);
                                }
                                break;
                            case 1:
                                p1 = A6;
                                p2 = new Point(pc.x, A6.y);
                                p3 = new Point(pc.x, B2.y);
                                p4 = B2;
                                break;
                            case 2:
                                tmpPoint = maiorPonto(A6, B5, false);
                                p1 = new Point(A6.x, tmpPoint.y);
                                p2 = new Point(B5.x, tmpPoint.y);
                                p4 = B4;
                                break;
                            case 3:
                                tmpPoint = maiorPonto(A6, B6, false);
                                p1 = new Point(A6.x, tmpPoint.y);
                                p2 = new Point(B6.x, tmpPoint.y);
                                break;
                        }
                        break;
                }
                break;
            // </editor-fold>

            // <editor-fold defaultstate="collapsed" desc="Case C">
            case 'C':
                switch (ladoA) {
                    case 0:
                        switch (ladoB) {
                            case 0:
                                p1 = A0;
                                p2 = new Point(A0.x, B0.y);
                                break;
                            case 1:
                                p1 = A0;
                                p2 = new Point(A0.x, pc.y);
                                p3 = new Point(B2.x, pc.y);
                                //p4 = B2;
                                break;
                            case 2:
                                p1 = A0;
                                if (pontoMaisProx(A0.y, A1.y, A7.y)) {
                                    p2 = A1;
                                    p3 = new Point(B4.x, A1.y);
                                } else {
                                    p2 = new Point(A1.x, pc.y);
                                    p3 = new Point(B4.x, pc.y);
                                }
                                p4 = B4;
                                break;
                            case 3:
                                p1 = A0;
                                p2 = new Point(A0.x, B6.y);
                                p3 = B6;
                                break;
                        }
                        break;
                    case 1:
                        switch (ladoB) {
                            case 0:
                                p1 = A2;
                                p2 = new Point(pc.x, A2.y);
                                p3 = new Point(pc.x, B0.y);
                                break;
                            case 1:
                                p1 = A2;
                                p2 = new Point(B2.x, A2.y);
                                break;
                            case 2:
                                p1 = A2;
                                p2 = new Point(B4.x, A2.y);
                                p3 = B4;
                                break;
                            case 3:
                                p1 = A2;
                                p2 = new Point(pc.x, A2.y);
                                p3 = new Point(pc.x, B6.y);
                                p4 = B6;
                                break;
                        }
                        break;
                    case 2:
                        switch (ladoB) {
                            case 0:
                                p1 = new Point(pc.x, A4.y);
                                p2 = new Point(pc.x, B0.y);
                                break;
                            case 1:
                                p1 = new Point(B2.x, A4.y);
                                break;
                            case 2:
                                p1 = new Point(B4.x, A4.y);
                                p2 = B4;
                                break;
                            case 3:
                                p1 = new Point(pc.x, A4.y);
                                p2 = new Point(pc.x, B6.y);
                                p3 = B6;
                                break;
                        }
                        break;
                    case 3:
                        switch (ladoB) {
                            case 0:
                                p1 = new Point(A6.x, B0.y);
                                break;
                            case 1:
                                p1 = new Point(A6.x, pc.y);
                                p2 = new Point(B2.x, pc.y);
                                break;
                            case 2:
                                p1 = new Point(A6.x, B3.y);
                                p2 = B3;
                                p4 = B4;
                                break;
                            case 3:
                                p1 = new Point(A6.x, B6.y);
                                p2 = B6;
                                break;
                        }
                        break;
                }
                break;
            // </editor-fold>

            // <editor-fold defaultstate="collapsed" desc="Case D">
            case 'D':
                switch (ladoA) {
                    case 0:
                        switch (ladoB) {
                            case 0:
                                tmpPoint = menorPonto(A0, B0, true);
                                p1 = new Point(tmpPoint.x, A0.y);
                                p2 = new Point(tmpPoint.x, B0.y);
                                break;
                            case 1:
                                if (pontaB.x + distancia > pontaA.x) {
                                    p1 = A0;
                                    p2 = new Point(A0.x, pc.y);
                                    p3 = new Point(B2.x, pc.y);
                                } else {
                                    p1 = new Point(B2.x, A0.y);
                                }
                                break;
                            case 2:
                                p1 = A0;
                                p2 = new Point(A0.x, pc.y);
                                p3 = new Point(B4.x, pc.y);
                                p4 = B4;
                                break;
                            case 3:
                                tmpPoint = menorPonto(A0, B7, true);
                                p1 = new Point(tmpPoint.x, A0.y);
                                p2 = new Point(tmpPoint.x, B7.y);
                                p3 = B6;
                                break;
                        }
                        break;
                    case 1:
                        switch (ladoB) {
                            case 0:
                                tmpPoint = menorPonto(A1, B0, true);
                                p1 = A2;
                                p2 = new Point(tmpPoint.x, A1.y);
                                p3 = new Point(tmpPoint.x, B0.y);
                                break;
                            case 1:
                                p1 = A2;
                                if (pontoMaisProx(A2.x, A1.x, A3.x)) {
                                    if (A1.x < pontaB.x) {
                                        p2 = A1;
                                        p3 = new Point(A1.x, B2.y);
                                        p4 = B2;
                                    } else {
                                        p2 = new Point(B2.x, A1.y);
                                    }
                                } else {
                                    if (A3.x > pontaB.x) {
                                        p2 = A3;
                                        p3 = new Point(A3.x, B2.y);
                                        p4 = B2;
                                    } else {
                                        p2 = new Point(B2.x, A3.y);
                                    }
                                }
                                break;
                            case 2:
                                p1 = A2;
                                tmpPoint = maiorPonto(A3, B4, true);
                                p2 = new Point(tmpPoint.x, A3.y);
                                p3 = new Point(tmpPoint.x, B4.y);
                                break;
                            case 3:
                                p1 = A2;
                                if (pontoMaisProx(A2.x, A1.x, A3.x)) {
                                    tmpPoint = menorPonto(A1, B7, true);
                                    p2 = new Point(tmpPoint.x, A1.y);
                                    p3 = new Point(tmpPoint.x, B7.y);
                                } else {
                                    tmpPoint = maiorPonto(A3, B5, true);
                                    p2 = new Point(tmpPoint.x, A3.y);
                                    p3 = new Point(tmpPoint.x, B5.y);
                                }

                                p4 = B6;
                                break;
                        }
                        break;
                    case 2:
                        switch (ladoB) {
                            case 0:
                                p1 = A4;
                                p2 = new Point(A4.x, pc.y);
                                p3 = new Point(B0.x, pc.y);
                                p4 = B0;
                                break;
                            case 1:
                                if (pontaA.x + distancia > pontaB.x) {
                                    p1 = A4;
                                    p2 = new Point(A4.x, pc.y);
                                    p3 = new Point(B2.x, pc.y);
                                } else {
                                    p1 = new Point(B2.x, A4.y);
                                }
                                break;
                            case 2:
                                tmpPoint = maiorPonto(A4, B4, true);
                                p1 = new Point(tmpPoint.x, A4.y);
                                p2 = new Point(tmpPoint.x, B4.y);
                                break;
                            case 3:
                                tmpPoint = maiorPonto(A4, B5, true);
                                p2 = new Point(tmpPoint.x, A4.y);
                                p3 = new Point(tmpPoint.x, B5.y);
                                p4 = B6;
                                break;
                        }
                        break;
                    case 3:
                        switch (ladoB) {
                            case 0:
                                if (A6.y > pontaB.y || A6.x > pontaB.x - distancia) {
                                    p1 = new Point(A6.x, pc.y);
                                    p2 = new Point(B1.x, pc.y);
                                    p3 = new Point(B1.x, pc.y);
                                    p4 = B0;
                                } else {
                                    p1 = new Point(A6.x, B0.y);
                                }

                                break;
                            case 1:
                                p1 = new Point(A6.x, pc.y);
                                p2 = new Point(B2.x, pc.y);
                                break;
                            case 2:
                                if (pontaA.x > pontaB.x + distancia) {
                                    p1 = new Point(A6.x, B4.y);
                                } else {
                                    p1 = new Point(A6.x, pc.y);
                                    p2 = new Point(B4.x, pc.y);
                                    p4 = B4;
                                }
                                break;
                            case 3:
                                if (A6.x < B0.x || A6.x > B4.x) {
                                    p1 = new Point(A6.x, B6.y);
                                    p2 = B6;
                                } else {
                                    p1 = new Point(A6.x, pc.y);
                                    if (pontoMaisProx(A6.x, A7.x, A5.x)) {
                                        p2 = new Point(B7.x, pc.y);
                                        p3 = B7;
                                    } else {
                                        p2 = new Point(B5.x, pc.y);
                                        p3 = B5;
                                    }
                                    p4 = B6;
                                }
                                break;
                        }
                        break;
                }
                break;
            // </editor-fold>

            // <editor-fold defaultstate="collapsed" desc="Case I">
            case 'I':
                switch (ladoA) {
                    case 0:
                        switch (ladoB) {
                            case 0:
                                p1 = A0;
                                p2 = new Point(A0.x, B0.y);
                                break;
                            case 1:
                                p1 = A0;
                                p2 = new Point(A0.x, B2.y);
                                p3 = B2;
                                break;
                            case 2:
                                p1 = A0;
                                p2 = new Point(A0.x, B3.y);
                                p3 = B3;
                                p4 = B4;
                                break;
                            case 3:
                                //p1 = A0;
                                //p2 = new Point(A0.x, pc.y);
                                //p3 = new Point(B6.x, pc.y);

                                p1 = A0;
                                tmpPoint = maiorPonto(A7, B6, false);
                                p2 = new Point(A7.x, tmpPoint.y);
                                p3 = new Point(B6.x, tmpPoint.y);

                                break;

                        }
                        break;
                    case 1:
                        switch (ladoB) {
                            case 0:
                                p1 = new Point(A2.x, B0.y);
                                break;
                            case 1:
                                p1 = new Point(A2.x, B2.y);
                                p2 = B2;
                                break;
                            case 2:
                                p1 = new Point(A2.x, pc.y);
                                p2 = new Point(B4.x, pc.y);
                                p3 = B4;
                                break;
                            case 3:
                                p1 = new Point(A2.x, pc.y);
                                p2 = new Point(B6.x, pc.y);
                                break;
                        }
                        break;
                    case 2:
                        switch (ladoB) {
                            case 0:
                                p1 = new Point(pc.x, A4.y);
                                p2 = new Point(pc.x, B0.y);
                                break;
                            case 1:
                                p1 = new Point(pc.x, A4.y);
                                p2 = new Point(pc.x, B2.y);
                                p3 = B2;
                                break;
                            case 2:
                                p1 = new Point(B4.x, A4.y);
                                p2 = B4;
                                break;
                            case 3:
                                p1 = new Point(B6.x, A4.y);
                                break;
                        }
                        break;
                    case 3:
                        switch (ladoB) {
                            case 0:
                                p1 = A6;
                                p2 = new Point(pc.x, A6.y);
                                p3 = new Point(pc.x, B0.y);
                                break;
                            case 1:
                                p1 = A6;
                                p2 = new Point(pc.x, A6.y);
                                p3 = new Point(pc.x, B2.y);
                                p4 = B2;
                                break;
                            case 2:
                                p1 = A6;
                                p2 = new Point(B4.x, A6.y);
                                p4 = B4;
                                break;
                            case 3:
                                p1 = A6;
                                p2 = new Point(B6.x, A6.y);
                                break;
                        }
                        break;
                }
                break;
            // </editor-fold>
            }

        ArrayList<PontoDeLinha> pontos = getPontos();
        while (pontos.size() > 2) {
            RemoveSubItem(pontos.get(pontos.size() - 2));
        }

        Point[] todos = inver ? new Point[]{p4, p3, p2, p1} : new Point[]{p1, p2, p3, p4};
        int tl = 0;
        boolean isvisi = getPontaA().isVisible();
        for (int i = 0; i < 4; i++) {
            if (todos[i] != null) {
                tl++;
                PontoDeLinha px = this.InserirPonto(tl);
                px.setVisible(isvisi);
                px.setCentro(todos[i]);
            }
        }
    }

    // <editor-fold defaultstate="collapsed" desc="Pontos: apoio para OrganizeLinha">
    /**
     * O ponto "quem" esta mais próximo "deste" em relação à "naoDeste"?
     * @param quem
     * @param deste
     * @param naoDeste
     * @return Sim ou Não!
     */
    private boolean pontoMaisProx(int quem, int deste, int naoDeste) {
        return (naoDeste - quem) > (quem - deste);
    }

    /**
     * Qual o maior ponto - porém o parâmetro "x" indica se será usada a coordenada X do ponto para a comparação, caso seja "false", será usada a coordenada Y.
     * @param A 
     * @param B
     * @param x - A.x e B.x se true, A.y e B.y se false!
     * @return 
     */
    private Point maiorPonto(Point A, Point B, boolean x) {
        if (x) {
            if (A.x > B.x) {

                return A;
            }
            return B;
        } else {
            if (A.y > B.y) {
                return A;
            }
            return B;
        }
    }
    
    /**
     * Qual o menor ponto - porém o parâmetro "x" indica se será usada a coordenada X do ponto para a comparação, caso seja "false", será usada a coordenada Y.
     * @param A 
     * @param B
     * @param x - A.x e B.x se true, A.y e B.y se false!
     * @return 
     */
    private Point menorPonto(Point A, Point B, boolean x) {
        if (x) {
            if (A.x < B.x) {

                return A;
            }
            return B;
        } else {
            if (A.y < B.y) {
                return A;
            }
            return B;
        }
    }
    // </editor-fold>


//    @Override
//    protected void ToXmlValores(Document doc, Element me) {
//        super.ToXmlValores(doc, me);
//        me.appendChild(util.XMLGenerate.ValorBoolean(doc, "Inteligente", isInteligente()));
//    }
    
    private PreTexto tag = null;

    public PreTexto getTag() {
        return tag;
    }

    public void setTag(PreTexto tag) {
        if (this.tag == tag) {
            return;
        }
        if (this.tag != null) {
            this.tag.SetLinhaMestre(null);
        }
        this.tag = tag;
        if (this.tag != null) {
            this.tag.SetLinhaMestre(this);
        }
    }

    public void SetTag(PreTexto tag) {
        if (this.tag == tag) {
            return;
        }
        this.tag = tag;
    }

    @Override
    public boolean Destroy() {
        setTag(null);
        return super.Destroy();
    }

    @Override
    public void reSetBounds() {
        SetaA = null;
        SetaB = null;
        super.reSetBounds();
        if (tag != null) {
            tag.Posicione();
        }
    }

    @Override
    protected void ToXmlValores(Document doc, Element me) {
        super.ToXmlValores(doc, me);
        Element lig = doc.createElement("Tag");
        util.XMLGenerate.AtributoRefFormElementar(lig, "LinhaMestre", getTag());
        me.appendChild(lig);
        me.appendChild(util.XMLGenerate.ValorBoolean(doc, "Dashed", isDashed()));
        me.appendChild(util.XMLGenerate.ValorBoolean(doc, "Ancorado", isAncorado()));

        if (showConfigSeta) {
            me.appendChild(util.XMLGenerate.ValorBoolean(doc, "TemSetaPontaA", isTemSetaPontaA()));
            me.appendChild(util.XMLGenerate.ValorBoolean(doc, "TemSetaPontaB", isTemSetaPontaB()));
            me.appendChild(util.XMLGenerate.ValorBoolean(doc, "SetaAberta", isSetaAberta()));
            me.appendChild(util.XMLGenerate.ValorInteger(doc, "SetaLargura", getSetaLargura()));
        }
    }

    @Override
    public boolean CommitXML(Element me, HashMap<Element, FormaElementar> mapa) {
        Element lig = util.XMLGenerate.FindByNodeName(me, "Tag");

        String stag = lig.getAttribute("LinhaMestre");
        FormaElementar resA = util.XMLGenerate.FindWhoHasID(stag, mapa);
        if (resA instanceof Texto) {
            setTag((PreTexto) resA);
        }
        return super.CommitXML(me, mapa);
    }

    @Override
    public boolean LoadFromXML(Element me, boolean colando) {
        setDashed(util.XMLGenerate.getValorBooleanFrom(me, "Dashed"));
        setAncorado(util.XMLGenerate.getValorBooleanFrom(me, "Ancorado"));

        if (showConfigSeta) {
            setTemSetaPontaA(util.XMLGenerate.getValorBooleanFrom(me, "TemSetaPontaA"));
            setTemSetaPontaB(util.XMLGenerate.getValorBooleanFrom(me, "TemSetaPontaB"));
            setSetaAberta(util.XMLGenerate.getValorBooleanFrom(me, "SetaAberta"));
            setSetaLargura(util.XMLGenerate.getValorIntegerFrom(me, "SetaLargura"));
        }
        return super.LoadFromXML(me, colando);
    }
    //<editor-fold defaultstate="collapsed" desc="Seta">
    private boolean temSetaPontaA = false;

    public boolean isTemSetaPontaA() {
        return temSetaPontaA;
    }

    public void setTemSetaPontaA(boolean temSetaPontaA) {
        if (this.temSetaPontaA == temSetaPontaA) {
            return;
        }
        this.temSetaPontaA = temSetaPontaA;
        Invalidate();
    }
    private boolean temSetaPontaB = false;

    public boolean isTemSetaPontaB() {
        return temSetaPontaB;
    }

    public void setTemSetaPontaB(boolean temSetaPontaB) {
        if (this.temSetaPontaB == temSetaPontaB) {
            return;
        }
        this.temSetaPontaB = temSetaPontaB;
        Invalidate();
    }
    protected int setaLargura = 10;

    public int getSetaLargura() {
        return setaLargura;
    }

    public void setSetaLargura(int setaLargura) {
        if (this.setaLargura == setaLargura) {
            return;
        }
        this.setaLargura = setaLargura;
        if (this.setaLargura > 99 || this.setaLargura < 10) {
            this.setaLargura = 10;
        }
        InvalidateArea();
        SetaA = null;
        SetaB = null;
    }

    /**
     * Desenha as setas
     *
     * @param g
     */
    public void paintSeta(Graphics2D g) {
        if (!(isTemSetaPontaA() || isTemSetaPontaB()) || !(showConfigSeta)) {
            return;
        }
        CalculeSetas();

        if (isTemSetaPontaA()) {
            g.fill(SetaA);
        }

        if (isTemSetaPontaB()) {
            g.fill(SetaB);
        }
    }

    private Shape SetaA = null;
    private Shape SetaB = null;

    private boolean setaAberta = true;

    public boolean isSetaAberta() {
        return setaAberta;
    }

    /**
     * Desenha as setas em forma de flecha?
     *
     * @param setaAberta
     */
    public void setSetaAberta(boolean setaAberta) {
        if (this.setaAberta != setaAberta) {
            this.setaAberta = setaAberta;
            InvalidateArea();
            SetaA = null;
            SetaB = null;
        }
    }

    @Override
    public void InvalidateArea() {
        super.InvalidateArea(); //To change body of generated methods, choose Tools | Templates.
        if (SetaA != null) {
            Rectangle r = SetaA.getBounds();
            InvalidateArea(r);
        }
        if (SetaB != null) {
            Rectangle r = SetaB.getBounds();
            InvalidateArea(r);
        }
    }

    @Override
    public boolean IsMe(Point p) {
        boolean im = super.IsMe(p); //To change body of generated methods, choose Tools | Templates.
        if (!im && (showConfigSeta) && (isTemSetaPontaA() || isTemSetaPontaB())) {
            if (SetaA != null) {
                im = SetaA.contains(p);
            }
            if ((!im) && SetaB != null) {
                im = SetaB.contains(p);
            }
        }
        return im;
    }

    /**
     * Cria os shapes das setas
     */
    protected void CalculeSetas() {
        if (!(isTemSetaPontaA() || isTemSetaPontaB()) || !(showConfigSeta)) {
            return;
        }
        int len = getSetaLargura() / 2;

        if (isTemSetaPontaA() && (SetaA == null)) {
            int x1 = getPontos().get(0).getCentro().x;
            int y1 = getPontos().get(0).getCentro().y;
            int x2 = getPontos().get(1).getCentro().x;
            int y2 = getPontos().get(1).getCentro().y;
            double dx = x2 - x1, dy = y2 - y1;
            double angle = Math.atan2(dy, dx);
            AffineTransform at = new AffineTransform();
            at.rotate(angle, x1, y1);

            Path2D res = new Path2D.Double();
            res.moveTo(x1, y1);
            res.lineTo(x1 + len, y1 - len);
            if (isSetaAberta()) {
                res.lineTo(x1 + 2, y1);
            }
            res.lineTo(x1 + len, y1 + len);
            res.lineTo(x1, y1);
            SetaA = res.createTransformedShape(at);
        }

        if (isTemSetaPontaB() && (SetaB == null)) {
            int tmp = getPontos().size() - 1;
            int x1 = getPontos().get(tmp).getCentro().x;
            int y1 = getPontos().get(tmp).getCentro().y;
            tmp--;
            int x2 = getPontos().get(tmp).getCentro().x;
            int y2 = getPontos().get(tmp).getCentro().y;
            double dx = x2 - x1, dy = y2 - y1;
            double angle = Math.atan2(dy, dx);

            AffineTransform at = new AffineTransform();
            at.rotate(angle, x1, y1);

            Path2D res = new Path2D.Double();
            res.moveTo(x1, y1);
            res.lineTo(x1 + len, y1 - len);
            if (isSetaAberta()) {
                res.lineTo(x1 + 2, y1);
            }
            res.lineTo(x1 + len, y1 + len);
            res.lineTo(x1, y1);
            SetaB = res.createTransformedShape(at);
        }
    }

    //</editor-fold>
    
    @Override
    public ArrayList<InspectorProperty> GenerateProperty() {
        ArrayList<InspectorProperty> res = super.GenerateProperty();
        res.add(InspectorProperty.PropertyFactorySN("ancorado", "setAncorado", isAncorado()));
        return res;
    }

    @Override
    public ArrayList<InspectorProperty> CompleteGenerateProperty(ArrayList<InspectorProperty> GP) {
        ArrayList<InspectorProperty> res = super.CompleteGenerateProperty(GP);
        res.add(InspectorProperty.PropertyFactorySN("linha.dashed", "setDashed", isDashed()));
        if (showConfigSeta) {
            res.add(InspectorProperty.PropertyFactorySeparador("seta.titulo"));
            res.add(InspectorProperty.PropertyFactorySN("seta.pontadireita", "setTemSetaPontaA", isTemSetaPontaA()));
            res.add(InspectorProperty.PropertyFactorySN("seta.pontaesquerda", "setTemSetaPontaB", isTemSetaPontaB()));
            res.add(InspectorProperty.PropertyFactorySN("seta.setaaberta", "setSetaAberta", isSetaAberta()));

            res.add(InspectorProperty.PropertyFactoryNumero("seta.largura", "setSetaLargura", getSetaLargura()));
        }
        return res;
    }

    @Override
    public void DoPaint(Graphics2D g) {
        super.DoPaint(g);
        paintSeta(g);
    }

//    /**
//     * É usado em linhas no futuro que usam texto apenso.
//     */
//    public void PrepareTexto() {
//    }
}