/* Copyright or (C) or Copr. GET / ENST, Telecom-Paris, Ludovic Apvrille
 *
 * ludovic.apvrille AT enst.fr
 *
 * This software is a computer program whose purpose is to allow the
 * edition of TURTLE analysis, design and deployment diagrams, to
 * allow the generation of RT-LOTOS or Java code from this diagram,
 * and at last to allow the analysis of formal validation traces
 * obtained from external tools, e.g. RTL from LAAS-CNRS and CADP
 * from INRIA Rhone-Alpes.
 *
 * This software is governed by the CeCILL  license under French law and
 * abiding by the rules of distribution of free software.  You can  use,
 * modify and/ or redistribute the software under the terms of the CeCILL
 * license as circulated by CEA, CNRS and INRIA at the following URL
 * "http://www.cecill.info".
 *
 * As a counterpart to the access to the source code and  rights to copy,
 * modify and redistribute granted by the license, users are provided only
 * with a limited warranty  and the software's author,  the holder of the
 * economic rights,  and the successive licensors  have only  limited
 * liability.
 *
 * In this respect, the user's attention is drawn to the risks associated
 * with loading,  using,  modifying and/or developing or reproducing the
 * software by the user in light of its specific status of free software,
 * that may mean  that it is complicated to manipulate,  and  that  also
 * therefore means  that it is reserved for developers  and  experienced
 * professionals having in-depth computer knowledge. Users are therefore
 * encouraged to load and test the software's suitability as regards their
 * requirements in conditions enabling the security of their systems and/or
 * data to be ensured and,  more generally, to use and operate it in the
 * same conditions as regards security.
 *
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL license and that you accept its terms.
 */

package ui.avatarbd;

import myutil.Conversion;
import myutil.GenericTree;
import myutil.GraphicLib;
import myutil.TraceManager;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import proverifspec.ProVerifResultTrace;
import proverifspec.ProVerifResultTraceStep;
import ui.*;
import ui.avatarsmd.AvatarSMDPanel;
import ui.interactivesimulation.JFrameSimulationSDPanel;
import ui.util.IconManager;
//import ui.window.JDialogAvatarBlock;
import ui.window.JDialogAvatarInterface;
import ui.window.JDialogIDAndStereotype;

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.util.*;
import java.util.List;

/**
 * Class AvatarBDInterface
 * Node. To be used in AVATAR Block Diagrams
 * Creation: 06/04/2010
 *
 * @author Ludovic APVRILLE
 * @version 1.1 06/04/2010
 */
public class AvatarBDInterface extends TGCScalableWithInternalComponent implements SwallowTGComponent, SwallowedTGComponent, GenericTree, AvatarBDStateMachineOwner, WithAttributes {

    private static String GLOBAL_CODE_INFO = "(block code)";

//    private int textY1 = 3;
//    private int textX = 7;

    private static String stereotype = "amsinterface";
    private static Color stereotypeColor = ColorManager.AVATAR_INTERFACE;


    private int maxFontSize = 12;
    //    private int minFontSize = 4;
    private int currentFontSize = -1;

    private int limitName = -1;
    private int limitAttr = -1;
    private int limitMethod = -1;
    private int limitSignal = -1;

    // Icon
    private int iconSize = 15;


    // TAttribute, AvatarMethod, AvatarSignal
    protected List<TAttribute> myAttributes;
    protected List<AvatarMethod> myMethods;
    protected List<AvatarSignal> mySignals;
    protected String[] globalCode;

    protected Map<TAttribute, ProVerifResultTrace> attrTraceMap = new HashMap<TAttribute, ProVerifResultTrace>();
    protected Map<TAttribute, Integer> attrLocMap = new HashMap<TAttribute, Integer>();

    public String oldValue;

    public AvatarBDInterface(int _x, int _y, int _minX, int _maxX, int _minY, int _maxY, boolean _pos, TGComponent _father, TDiagramPanel _tdp) {
        super(_x, _y, _minX, _maxX, _minY, _maxY, _pos, _father, _tdp);

        width = 250;
        height = 200;
        minWidth = 5;
        minHeight = 2;
        textY = 3;
        textX = 7;
        initScaling(250, 200);


        nbConnectingPoint = 16;
        connectingPoint = new TGConnectingPoint[16];

        connectingPoint[0] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 0.0, 0.0);
        connectingPoint[1] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 0.5, 0.0);
        connectingPoint[2] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 1.0, 0.0);
        connectingPoint[3] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 0.0, 0.5);
        connectingPoint[4] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 1.0, 0.5);
        connectingPoint[5] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 0.0, 1.0);
        connectingPoint[6] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 0.5, 1.0);
        connectingPoint[7] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 1.0, 1.0);

        connectingPoint[8] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 0.25, 0.0);
        connectingPoint[9] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 0.75, 0.0);
        connectingPoint[10] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 0.0, 0.25);
        connectingPoint[11] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 1.0, 0.25);
        connectingPoint[12] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 0.0, 0.75);
        connectingPoint[13] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 1.0, 0.75);
        connectingPoint[14] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 0.25, 1.0);
        connectingPoint[15] = new AvatarBDConnectingPoint(this, 0, 0, true, true, 0.75, 1.0);

        addTGConnectingPointsComment();

        nbInternalTGComponent = 0;

        moveable = true;
        editable = true;
        multieditable = true;
        removable = true;
        userResizable = true;

        name = tdp.findAvatarBDInterfaceName("Interface");
        setValue(name);
        oldValue = value;

        oldScaleFactor = tdp.getZoom();
        currentFontSize = (int) (maxFontSize * oldScaleFactor);

        //myImageIcon = IconManager.imgic700;
	myImageIcon = IconManager.imgic700;

        this.myAttributes = new LinkedList<TAttribute>();
        this.myMethods = new LinkedList<AvatarMethod>();
        this.mySignals = new LinkedList<AvatarSignal>();

        actionOnAdd();
    }

    @Override
    public void internalDrawing(Graphics graph) {
        Font font = graph.getFont();
        this.internalDrawingAux(graph);
        graph.setFont(font);
    }

    public void addProVerifTrace(TAttribute attr, ProVerifResultTrace trace) {
        attrTraceMap.put(attr, trace);
    }

    public void setSignalsAsNonAttached() {
        for (AvatarSignal mySig : mySignals) mySig.attachedToARelation = false;
    }

    public void addSignal(AvatarSignal sig) {
        this.mySignals.add(sig);
    }

    /**
     * Issue #31: text disappearance
     *
     * @param graph
     */
    private void internalDrawingAux(Graphics graph) {
        //Rectangle
        Color c = graph.getColor();
        graph.drawRect(this.x, this.y, this.width, this.height);
        graph.setColor(stereotypeColor);
        graph.fillRect(this.x + 1, this.y + 1, this.width - 1, this.height - 1);
        graph.setColor(c);

        //string
        int h = graph.getFontMetrics().getAscent() + graph.getFontMetrics().getLeading() + textY;

        if (h + graph.getFontMetrics().getDescent() + textY >= this.height)
            return;
        Font f = graph.getFont();

        // limits
//        this.limitName = -1;
//        this.limitAttr = -1;
//        this.limitMethod = -1;
//        this.limitSignal = y + height;
//
//        // h retains the coordinate along X where an element was last drawn
//        int h = 0;
//
//        int textY1 = (int) (this.textY1 * this.tdp.getZoom());
//        int textX = (int) (this.textX * this.tdp.getZoom());
//
//        // Draw icon
//        this.iconIsDrawn = this.width > IconManager.iconSize + 2 * textX && height > IconManager.iconSize + 2 * textX;
//        if (this.iconIsDrawn) {
//            graph.drawImage(IconManager.img5100, this.x + this.width - IconManager.iconSize - textX, this.y + textX, null);
//        }
//
//
//        Font font = graph.getFont();


        String ster = stereotype;
        int w = graph.getFontMetrics().stringWidth(ster);
        h = graph.getFontMetrics().getAscent() + graph.getFontMetrics().getLeading() + textY;
        graph.setFont(f.deriveFont(Font.BOLD));
        if (w + 2 * textX < this.width)
            drawSingleString(graph, ster, getCenter(graph, ster), this.y + h);
        h += graph.getFontMetrics().getHeight() + textY;
        w = graph.getFontMetrics().stringWidth(value);
        graph.setFont(f.deriveFont(Font.PLAIN));
        if (w + 2 * textX < this.width)
            drawSingleString(graph, this.value, getCenter(graph, value), this.y + h);

        //draw separator
        this.limitName = this.y + h;
        //TraceManager.addDev("limitName=" + limitName);

        if (h + textY >= this.height)
            return;
        h += graph.getFontMetrics().getDescent() + textY;
        //if (canTextGoInTheBox(graph, h, "line", 0));
        graph.drawLine(this.x, this.y + h, this.x + this.width, this.y + h);
        h += textY;

        //Attributes
        if (!this.tdp.areAttributesVisible())
            return;
        int attributeFontSize = f.getSize() * 5 / 6;
        graph.setFont(f.deriveFont((float) attributeFontSize));
        int step = graph.getFontMetrics().getHeight();
        h += textY;
        limitAttr = limitName;
        for (TAttribute attr : this.myAttributes) {
            h += step;
            if (h >= this.height - textX) {
                this.limitAttr = this.y + this.height;
                return;
            }

            // Get the string for this parameter
            String attrString = attr.toAvatarString();
            w = graph.getFontMetrics().stringWidth(attrString);
            attrLocMap.put(attr, this.y + h);
            if (w + 2 * textX < this.width) {
                //graph.drawString(attrString, this.x + textX, this.y + h);
                drawSingleString(graph, attrString, this.x + textX, this.y + h);
                this.drawConfidentialityVerification(attr.getConfidentialityVerification(), graph, this.x, this.y + h);
            }
        }

        //ICON
        drawImageWithCheck(graph, IconManager.img5100, this.x + this.width - scale(IconManager.iconSize) - textX, this.y + textX);


        // Remember the end of attributes
        this.limitAttr = this.y + h;
        if (h + textY >= this.height)
            return;

        h += graph.getFontMetrics().getDescent();

        graph.drawLine(this.x, this.y + h, this.x + this.width, this.y + h);
        h += textY;

        // Methods
        limitMethod = limitAttr;
        limitSignal = limitAttr;

        for (AvatarMethod method : this.myMethods) {
            h += step;
            if (h >= this.height - textX) {
                this.limitMethod = this.y + this.height;
                this.limitSignal = limitMethod;
                return;
            }

            // Get the string for this method
            String methodString = "- " + method.toString();

            w = graph.getFontMetrics().stringWidth(methodString);
            if (w + 2 * textX < this.width)
                drawSingleString(graph, methodString, this.x + textX, this.y + h);
            else {
                // If we can't, try to draw with "..." instead
                int stringLength;
                for (stringLength = methodString.length() - 1; stringLength >= 0; stringLength--) {
                    String abbrev = methodString.substring(0, stringLength) + "...";
                    w = graph.getFontMetrics().stringWidth(abbrev);
                    if (w + 2 * textX < this.width) {
                        drawSingleString(graph, abbrev, this.x + textX, this.y + h);
                        break;
                    }
                }

                if (stringLength < 0)
                    // skip method
                    h -= step;
            }
        }

        h += graph.getFontMetrics().getDescent() + textY;

        if (h + textY >= this.height) {
            limitMethod = this.y + this.height;
            limitSignal = this.y + this.height;
            return;
        }

        // Remember limit of methods
        this.limitMethod = this.y + h;
        this.limitSignal = this.y + h;

        graph.drawLine(this.x, this.y + h, this.x + this.width, this.y + h);
        h += textY;

        // Signals
        for (AvatarSignal signal : this.mySignals) {
            h += step;
            if (h >= this.height - textX) {
                limitSignal = this.height + this.y;
                return;
            }

            String signalString = "~ " + signal.toString();
            w = graph.getFontMetrics().stringWidth(signalString);
            if (w + 2 * textX < this.width) {
//                graph.drawString(signalString, this.x + textX, this.y + h);
                drawSingleString(graph, signalString, this.x + textX, this.y + h);
                drawInfoAttachement(signal, graph, x, y + h);

            } else {
                // If we can't, try to draw with "..." instead
                int stringLength;
                for (stringLength = signalString.length() - 1; stringLength >= 0; stringLength--) {
                    String abbrev = signalString.substring(0, stringLength) + "...";
                    w = graph.getFontMetrics().stringWidth(abbrev);
                    if (w + 2 * textX < this.width) {
                        //graph.drawString(abbrev, this.x + textX, this.y + h);
                        drawSingleString(graph, abbrev, this.x + textX, this.y + h);
                        drawInfoAttachement(signal, graph, x, y + h);
                        break;
                    }
                }

                if (stringLength < 0)
                    // skip signal
                    h -= step;
            }
        }

        h += graph.getFontMetrics().getDescent() + textY;

        if (h + textY >= this.height) {
            limitSignal = this.height + this.y;
            return;
        }

        // Global code
        limitSignal = this.y + h;
        if (hasGlobalCode()) {
            if (h + textY + step >= this.height - textX)
                return;
            graph.drawLine(this.x, this.y + h, this.x + this.width, this.y + h);
            h += textY + step;

            w = graph.getFontMetrics().stringWidth(GLOBAL_CODE_INFO);
            if (w + 2 * textX < this.width)
                drawSingleString(graph, GLOBAL_CODE_INFO, this.x + (this.width - w) / 2, this.y + h);
//                graph.drawString(GLOBAL_CODE_INFO, this.x + (this.width - w) / 2, this.y + h);
        } else {
            limitSignal = height;
        }

    }

//    private void internalDrawingAu(Graphics graph) {
//
//        //TraceManager.addDev("Interface drawing aux = " + this);
//
//        // Draw outer rectangle (for border)
//        Color c = graph.getColor();
//        graph.drawRect(this.x, this.y, this.width, this.height);
//
//        // Draw inner rectangle
//        //graph.setColor(ColorManager.AVATAR_BLOCK);
//
//        //TraceManager.addDev("type stereotype=" + typeStereotype);
//
//        graph.setColor(BLOCK_TYPE_COLOR.get(typeStereotype));
//        graph.fillRect(this.x + 1, this.y + 1, this.width - 1, this.height - 1);
//        graph.setColor(c);
//
//        // limits
//        this.limitName = -1;
//        this.limitAttr = -1;
//        this.limitMethod = -1;
//        this.limitSignal = y + height;
//
//        // h retains the coordinate along X where an element was last drawn
//        int h = 0;
//
////        int textY1 = (int) (this.textY1 * this.tdp.getZoom());
////        int textX = (int) (this.textX * this.tdp.getZoom());
//
//        // Draw icon
//        this.iconIsDrawn = this.width > IconManager.iconSize + 2 * textX && height > IconManager.iconSize + 2 * textX;
//        if (this.iconIsDrawn)
//            graph.drawImage(scale(IconManager.img5100), this.x + this.width - scale(IconManager.iconSize) - textX, this.y + textX, null);
//
//
//        Font font = graph.getFont();
//
//
//        String ster = BLOCK_TYPE_STR.get(typeStereotype);
//
//        //TraceManager.addDev("My ster=" + ster);
//
//        if (this.rescaled && !this.tdp.isScaled()) {
//            this.rescaled = false;
//            // Must set the font size...
//            // Incrementally find the biggest font not greater than max_font size
//            // If font is less than min_font, no text is displayed
//
//            // This is the maximum font size possible
//            int maxCurrentFontSize = Math.max(0, Math.min(this.height, (int) (this.maxFontSize * this.tdp.getZoom())));
//            font = font.deriveFont((float) maxCurrentFontSize);
//
//            // Try to decrease font size until we get below the minimum
//            while (maxCurrentFontSize > (this.minFontSize * this.tdp.getZoom() - 1)) {
//                // Compute width of name of the function
//                int w0 = graph.getFontMetrics(font).stringWidth(this.value);
//                // Compute width of string stereotype
//                int w1 = graph.getFontMetrics(font).stringWidth(ster);
//
//                // if one of the two width is small enough use this font size
//                if (Math.min(w0, w1) < this.width - (2 * this.textX))
//                    break;
//
//                // Decrease font size
//                maxCurrentFontSize--;
//                // Scale the font
//                font = font.deriveFont((float) maxCurrentFontSize);
//            }
//
//            // Box is too damn small
//            if (this.currentFontSize < this.minFontSize * this.tdp.getZoom()) {
//                maxCurrentFontSize++;
//                // Scale the font
//                font = font.deriveFont((float) maxCurrentFontSize);
//            }
//
//            // Use this font
//            graph.setFont(font);
//            this.currentFontSize = maxCurrentFontSize;
//        } else
//            font = font.deriveFont(this.currentFontSize);
//
//        graph.setFont(font.deriveFont(Font.BOLD));
//        h = graph.getFontMetrics().getAscent() + graph.getFontMetrics().getLeading() + textY;
//
//        if (h + graph.getFontMetrics().getDescent() + textY >= this.height)
//            return;
//
//        // Write stereotype if small enough
//        int w = graph.getFontMetrics().stringWidth(ster);
//        if (w + 2 * textX < this.width)
////            graph.drawString(ster, this.x + (this.width - w) / 2, this.y + h);
//        	drawSingleString(graph, ster, this.x + (this.width - w) / 2, this.y + h);
//        else {
//            // try to draw with "..." instead
//            if (!this.isCryptoBlock())
//                ster = stereotype;
//            else
//                ster = stereotypeCrypto;
//
//            for (int stringLength = ster.length() - 1; stringLength >= 0; stringLength--) {
//                String abbrev = "<<" + ster.substring(0, stringLength) + "...>>";
//                w = graph.getFontMetrics().stringWidth(abbrev);
//                if (w + 2 * textX < this.width) {
////                    graph.drawString(abbrev, this.x + (this.width - w) / 2, this.y + h);
//                	drawSingleString(graph, abbrev, this.x + (this.width - w) / 2, this.y + h);
//                    break;
//                }
//            }
//        }
//
//        // Write value if small enough
//        graph.setFont(font);
//        h += graph.getFontMetrics().getHeight() + textY;
//        if (h + graph.getFontMetrics().getDescent() + textY >= this.height)
//            return;
//
//        w = graph.getFontMetrics().stringWidth(this.value);
//        if (w + 2 * textX < this.width)
//            graph.drawString(this.value, this.x + (this.width - w) / 2, this.y + h);
//        else {
//            // try to draw with "..." instead
//            for (int stringLength = this.value.length() - 1; stringLength >= 0; stringLength--) {
//                String abbrev = this.value.substring(0, stringLength) + "...";
//                w = graph.getFontMetrics().stringWidth(abbrev);
//                if (w + 2 * textX < this.width) {
//                    graph.drawString(abbrev, this.x + (this.width - w) / 2, this.y + h);
//                    break;
//                }
//            }
//        }
//
//        h += graph.getFontMetrics().getDescent() + textY;
//
//        // Update lower bound of text
//        this.limitName = this.y + h;
//
//        if (h + textY >= this.height)
//            return;
//
//        // Draw separator
//        graph.drawLine(this.x, this.y + h, this.x + this.width, this.y + h);
//
//        if (!this.tdp.areAttributesVisible())
//            return;
//
//        // Set font size
//        // int attributeFontSize = Math.min (12, this.currentFontSize - 2);
//        int attributeFontSize = this.currentFontSize * 5 / 6;
//        graph.setFont(font.deriveFont((float) attributeFontSize));
//        int step = graph.getFontMetrics().getHeight();
//
//        h += textY;
//
//        // Attributes
//        limitAttr = limitName;
//        for (TAttribute attr : this.myAttributes) {
//            h += step;
//            if (h >= this.height - textX) {
//                this.limitAttr = this.y + this.height;
//                return;
//            }
//
//            // Get the string for this parameter
//            String attrString = attr.toAvatarString();
//
//            // Try to draw it
//            w = graph.getFontMetrics().stringWidth(attrString);
//            
//            attrLocMap.put(attr,this.y+h);
//            if (w + 2 * textX < this.width) {
//                graph.drawString(attrString, this.x + textX, this.y + h);
//                this.drawConfidentialityVerification(attr.getConfidentialityVerification(), graph, this.x, this.y + h);
//            } else {
//                // If we can't, try to draw with "..." instead
//                int stringLength;
//                for (stringLength = attrString.length() - 1; stringLength >= 0; stringLength--) {
//                    String abbrev = attrString.substring(0, stringLength) + "...";
//                    w = graph.getFontMetrics().stringWidth(abbrev);
//                    if (w + 2 * textX < this.width) {
//                        graph.drawString(abbrev, this.x + textX, this.y + h);
//                        this.drawConfidentialityVerification(attr.getConfidentialityVerification(), graph, this.x, this.y + h);
//                        break;
//                    }
//                }
//
//                if (stringLength < 0)
//                    // skip attribute
//                    h -= step;
//            }
//        }
//
//        h += graph.getFontMetrics().getDescent() + textY;
//
//        // Remember the end of attributes
//        this.limitAttr = this.y + h;
//
//        if (h + textY >= this.height)
//            return;
//
//        graph.drawLine(this.x, this.y + h, this.x + this.width, this.y + h);
//        h += textY;
//
//        // Methods
//        limitMethod = limitAttr;
//        limitSignal = limitAttr;
//        for (AvatarMethod method : this.myMethods) {
//            h += step;
//            if (h >= this.height - textX) {
//                this.limitMethod = this.y + this.height;
//                this.limitSignal = limitMethod;
//                return;
//            }
//
//            // Get the string for this method
//            String methodString = "- " + method.toString();
//
//            w = graph.getFontMetrics().stringWidth(methodString);
//            if (w + 2 * textX < this.width)
//                graph.drawString(methodString, this.x + textX, this.y + h);
//            else {
//                // If we can't, try to draw with "..." instead
//                int stringLength;
//                for (stringLength = methodString.length() - 1; stringLength >= 0; stringLength--) {
//                    String abbrev = methodString.substring(0, stringLength) + "...";
//                    w = graph.getFontMetrics().stringWidth(abbrev);
//                    if (w + 2 * textX < this.width) {
//                        graph.drawString(abbrev, this.x + textX, this.y + h);
//                        break;
//                    }
//                }
//
//                if (stringLength < 0)
//                    // skip method
//                    h -= step;
//            }
//        }
//
//        h += graph.getFontMetrics().getDescent() + textY;
//
//        if (h + textY >= this.height) {
//            limitMethod = this.y + this.height;
//            limitSignal = this.y + this.height;
//            return;
//        }
//
//        // Remember limit of methods
//        this.limitMethod = this.y + h;
//        this.limitSignal = this.y + h;
//
//        graph.drawLine(this.x, this.y + h, this.x + this.width, this.y + h);
//        h += textY;
//
//        // Signals
//        for (AvatarSignal signal : this.mySignals) {
//            h += step;
//            if (h >= this.height - textX) {
//                limitSignal = this.height + this.y;
//                return;
//            }
//
//            String signalString = "~ " + signal.toString();
//            w = graph.getFontMetrics().stringWidth(signalString);
//            if (w + 2 * textX < this.width) {
//                graph.drawString(signalString, this.x + textX, this.y + h);
//                drawInfoAttachement(signal, graph, x, y + h);
//
//            } else {
//                // If we can't, try to draw with "..." instead
//                int stringLength;
//                for (stringLength = signalString.length() - 1; stringLength >= 0; stringLength--) {
//                    String abbrev = signalString.substring(0, stringLength) + "...";
//                    w = graph.getFontMetrics().stringWidth(abbrev);
//                    if (w + 2 * textX < this.width) {
//                        graph.drawString(abbrev, this.x + textX, this.y + h);
//                        drawInfoAttachement(signal, graph, x, y + h);
//
//
//                        break;
//                    }
//                }
//
//                if (stringLength < 0)
//                    // skip signal
//                    h -= step;
//            }
//        }
//
//        h += graph.getFontMetrics().getDescent() + textY;
//
//        if (h + textY >= this.height) {
//            limitSignal = this.height + this.y;
//            return;
//        }
//
//        // Global code
//        limitSignal = this.y + h;
//        if (hasGlobalCode()) {
//            if (h + textY + step >= this.height - textX)
//                return;
//            graph.drawLine(this.x, this.y + h, this.x + this.width, this.y + h);
//            h += textY + step;
//
//            w = graph.getFontMetrics().stringWidth(GLOBAL_CODE_INFO);
//            if (w + 2 * textX < this.width)
//                graph.drawString(GLOBAL_CODE_INFO, this.x + (this.width - w) / 2, this.y + h);
//        } else {
//            limitSignal = height;
//        }
//    }

    private void drawInfoAttachement(AvatarSignal _as, Graphics g, int _x, int _y) {
        if (_as.attachedToARelation) {
            return;
        }
        Color c = g.getColor();
        g.setColor(Color.RED);
        int[] xA = new int[3];
        int[] yA = new int[3];
        //top of triangle
        xA[0] = _x + 5;
        yA[0] = _y - 7;

        // Right bottom point
        xA[1] = _x + 2;
        yA[1] = _y;

        // Left bottom point
        xA[2] = _x + 8;
        yA[2] = _y;

        g.fillPolygon(xA, yA, 3);

        g.setColor(c);
    }

    public void showTrace(int y) {

        if (y < limitAttr) {
            for (TAttribute attr : attrLocMap.keySet()) {
                if (attrLocMap.get(attr) < y && y < attrLocMap.get(attr) + currentFontSize && attrTraceMap.get(attr) != null) {
                    PipedOutputStream pos = new PipedOutputStream();
                    try {
                        PipedInputStream pis = new PipedInputStream(pos, 4096);
                        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(pos));

                        JFrameSimulationSDPanel jfssdp = new JFrameSimulationSDPanel(null, tdp.getMGUI(), "Confidentiality " + attr.toString());
                        jfssdp.setIconImage(IconManager.img8);
                        GraphicLib.centerOnParent(jfssdp, 600, 600);
                        jfssdp.setFileReference(new BufferedReader(new InputStreamReader(pis)));
                        jfssdp.setVisible(true);
                        //jfssdp.setModalExclusionType(ModalExclusionType
                        //      .APPLICATION_EXCLUDE);
                        jfssdp.toFront();

                        // TraceManager.addDev("\n--- Trace ---");
                        int i = 0;
                        for (ProVerifResultTraceStep step : attrTraceMap.get(attr).getTrace()) {
                            step.describeAsTMLSDTransaction(bw, i);
                            i++;
                        }
                        bw.close();
                    } catch (IOException e) {
                        TraceManager.addDev("Error when writing trace step SD transaction");
                    } finally {
                        try {
                            pos.close();
                        } catch (IOException ignored) {
                        }
                    }

                }
            }
        }
    }

    private void drawConfidentialityVerification(int confidentialityVerification, Graphics g, int _x, int _y) {
        Color c = g.getColor();
        Color c1;
        int xc = (int) (6 * tdp.getZoom());
        int yc = (int) (10 * tdp.getZoom());
        int lockwidth = (int) (9 * tdp.getZoom());
        int lockheight = (int) (7 * tdp.getZoom());
        int ovalwidth = (int) (6 * tdp.getZoom());
        int ovalheight = (int) (9 * tdp.getZoom());
        switch (confidentialityVerification) {
            case TAttribute.CONFIDENTIALITY_OK:
                c1 = Color.green;
                break;
            case TAttribute.CONFIDENTIALITY_KO:
                c1 = Color.red;
                break;
            case TAttribute.COULD_NOT_VERIFY_CONFIDENTIALITY:
                c1 = Color.orange;
                break;
            default:
                return;
        }

        g.drawOval(_x + xc, _y - yc, ovalwidth, ovalheight);
        g.setColor(c1);
        g.fillRect(_x + xc * 2 / 3, _y - yc * 2 / 3, lockwidth, lockheight);
        g.setColor(c);
        g.drawRect(_x + xc * 2 / 3, _y - yc * 2 / 3, lockwidth, lockheight);

    }

    @Override
    public TGComponent isOnOnlyMe(int x1, int y1) {
        if (GraphicLib.isInRectangle(x1, y1, x, y, width, height)) {
            return this;
        }
        return null;
    }

    public String getStereotype() {
        return stereotype;
    }

    public String getNodeName() {
        return name;
    }

    public String getFullyQualifiedName() {
        String result = "";
        if (this.father != null && (this.father instanceof AvatarBDInterface)) {
            result = ((AvatarBDInterface) this.father).getFullyQualifiedName() + ".";
        }
        result += this.value;

        return result;
    }

    @Override
    public boolean editOnDoubleClick(JFrame frame, int _x, int _y) {
        int textX = (int) (this.textX * this.tdp.getZoom());

        if (GraphicLib.isInRectangle(_x, _y, x + width - iconSize - textX, y + textX, iconSize, iconSize)) {
            tdp.getMouseManager().setSelection(-1, -1);
            tdp.selectTab(getValue());
            return true;
        }

        // On the name ?
        //TraceManager.addDev("_y=" + _y + " limitName=" + limitName);
        if ((limitName == -1) || _y < limitName) {
            String s = (String) JOptionPane.showInputDialog(frame, "Library Function Name",
                    "setting value", JOptionPane.PLAIN_MESSAGE, IconManager.imgic101,
                    null,
                    this.getValue());

            if ((s != null) && (s.length() > 0)) {
                //boolean b;
                if (!s.equals(oldValue)) {
                    if (!TAttribute.isAValidId(s, false, false, false)) {
                        JOptionPane.showMessageDialog(frame,
                                "Could not change the name of the Interface: the new name is not a valid name",
                                "Error",
                                JOptionPane.INFORMATION_MESSAGE);
                        return false;
                    }

		    /*    if (!tdp.isAvatarInterfaceNameUnique(s)) {
                        JOptionPane.showMessageDialog(frame,
                                "Could not change the name of the Interface: the new name is already in use",
                                "Error",
                                JOptionPane.INFORMATION_MESSAGE);
                        return false;
			}*/

                    setValue(s);
                    recalculateSize();

                    if (!(tdp.actionOnDoubleClick(this))) {
                        JOptionPane.showMessageDialog(frame,
                                "Could not change the name of the Interface: this name is already in use",
                                "Error",
                                JOptionPane.INFORMATION_MESSAGE);
                        setValue(oldValue);
                        return false;
                    }


                }




                return true;

            }


            return false;
        }

        // And so -> attributes!

        int tab = 0;

        //TraceManager.addDev("limitAttr=" + limitAttr + " method=" + limitMethod + " limitSignal=" + limitSignal + " y=" + _y + " height=" + height);

        if (limitMethod == -1) {
            limitMethod = limitAttr;
        }

        if (limitSignal == -1) {
            limitSignal = limitMethod;
        }

        if (limitAttr == -1) {
            tab = 0;
        } else {
            if (_y < limitAttr) {
                tab = 0;
            } else if (_y < limitMethod) {
                tab = 1;
            } else if (_y < limitSignal) {
                tab = 2;
            } else if (_y > limitSignal && hasGlobalCode()) {
                tab = 3;
            } else if (_y > limitSignal && !hasGlobalCode()) {
                tab = 2;
            }
        }

        /*if (limitAttr != -1) {
            if (_y > limitAttr) {
                if (limitMethod == -1) {
                    tab = 2;
                } else {
                    tab = 1;
                }
            }
        }
        if (limitMethod != -1) {
            if (_y > limitMethod) {
                tab = 2;
            }
        }

        if ((limitMethod == -1) && (limitAttr == -1)) {
            if (this.mySignals.size() > 1) {
                tab = 2;
            }
	    }*/

        String mainCode = null;
        TDiagramPanel ttdp = getTDiagramPanel();
        if (ttdp instanceof AvatarBDPanel) {
            mainCode = ((AvatarBDPanel) (ttdp)).getMainCode();
        }
        JDialogAvatarInterface jdab = new JDialogAvatarInterface(this.myAttributes, this.myMethods, this.mySignals, null, frame, "Setting attributes of " + value, "Attribute", tab, globalCode, true, mainCode);
        setJDialogOptions(jdab);
//        jdab.setSize(650, 575);
        GraphicLib.centerOnParent(jdab, 780, 700);
        jdab.setVisible(true); // blocked until dialog has been closed
        //makeValue();
        //if (oldValue.equals(value)) {
        //return false;
        //}

        if (!jdab.hasBeenCancelled()) {
            globalCode = jdab.getGlobalCode();
            String tmp = jdab.getMainCode();
            if (tmp != null) {
                ((AvatarBDPanel) (ttdp)).setMainCode(tmp);
            }
        }

        ((AvatarBDPanel) tdp).updateAllSignalsOnConnectors();
        rescaled = true;
        return true;
    }

    protected void setJDialogOptions(JDialogAvatarInterface _jdab) {
        //jda.addAccess(TAttribute.getStringAccess(TAttribute.PUBLIC));
        _jdab.addAccess(TAttribute.getStringAccess(TAttribute.PRIVATE));
        //_jdab.addType(TAttribute.getStringType(TAttribute.NATURAL), true);
        _jdab.addType(TAttribute.getStringAvatarType(TAttribute.BOOLEAN), true);
        _jdab.addType(TAttribute.getStringAvatarType(TAttribute.INTEGER), true);
        _jdab.addType(TAttribute.getStringType(TAttribute.TIMER), false);

        for (String s : tdp.getAllDataTypes()) {
            _jdab.addType(s, false);
        }

        _jdab.enableInitialValue(true);
        _jdab.enableRTLOTOSKeyword(false);
        _jdab.enableJavaKeyword(false);
        _jdab.enableUPPAALKeyword(false);
    }

    @Override
    public int getType() {
        return TGComponentManager.AVATARBD_AMS_INTERFACE;
    }

    @Override
    public boolean acceptSwallowedTGComponent(TGComponent tgc) {
        return tgc instanceof AvatarBDInterface || tgc instanceof AvatarBDLibraryFunction;

    }

    @Override
    public boolean addSwallowedTGComponent(TGComponent tgc, int x, int y) {
        boolean swallowed = false;

        for (int i = 0; i < nbInternalTGComponent; i++) {
            if (tgcomponent[i] instanceof SwallowTGComponent) {
                if (tgcomponent[i].isOnMe(x, y) != null) {
                    swallowed = true;
                    ((SwallowTGComponent) tgcomponent[i]).addSwallowedTGComponent(tgc, x, y);
                    break;
                }
            }
        }

        if (swallowed) {
            return true;
        }

        if (!acceptSwallowedTGComponent(tgc)) {
            return false;
        }

        //
        // Choose its position

        // Make it an internal component
        // It's one of my son
        tgc.setFather(this);
        tgc.setDrawingZone(true);

        //Set its coordinates
        if (tgc instanceof AvatarBDInterface) {
            //tgc.setCdRectangle((width/2) - tgc.getWidth(), (width/2), spacePt, height-spacePt);
            //
            tgc.resizeWithFather();
            //tgc.setCdRectangle(0, width - tgc.getWidth(), 0, height - tgc.getHeight());
            //tgc.setCd(x, y);
        } else if (tgc instanceof AvatarBDLibraryFunction)
            tgc.resizeWithFather();

        // else unknown*/

        //add it
        addInternalComponent(tgc, 0);

        return true;
    }

    @Override
    public void removeSwallowedTGComponent(TGComponent tgc) {
        removeMyInternalComponent(tgc, false);
    }

    public boolean removeMyInternalComponent(TGComponent tgc, boolean actionOnRemove) {
        //TGComponent tgc;
        for (int i = 0; i < nbInternalTGComponent; i++) {
            if (tgcomponent[i] == tgc) {
                nbInternalTGComponent = nbInternalTGComponent - 1;
                if (nbInternalTGComponent == 0) {
                    tgcomponent = null;
                } else {
                    TGComponent[] tgcomponentbis = new TGComponent[nbInternalTGComponent];
                    for (int j = 0; j < nbInternalTGComponent; j++) {
                        if (j < i) {
                            tgcomponentbis[j] = tgcomponent[j];
                        }
                        if (j >= i) {
                            tgcomponentbis[j] = tgcomponent[j + 1];
                        }
                    }
                    tgcomponent = tgcomponentbis;
                }
                if (actionOnRemove) {
                    tgc.actionOnRemove();
                    tdp.actionOnRemove(tgc);
                }
                return true;
            } else {
                if (((AvatarBDInterface) tgcomponent[i]).removeMyInternalComponent(tgc, false)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    protected String translateExtraParam() {
        StringBuffer sb = new StringBuffer("<extraparam>\n");

        for (TAttribute a : this.myAttributes) {
            sb.append("<Attribute access=\"");
            sb.append(a.getAccess());
            sb.append("\" id=\"");
            sb.append(a.getId());
            sb.append("\" value=\"");
            sb.append(a.getInitialValue());
            sb.append("\" type=\"");
            sb.append(a.getType());
            sb.append("\" typeOther=\"");
            sb.append(a.getTypeOther());
            sb.append("\" />\n");
        }
        for (AvatarMethod am : this.myMethods) {
            sb.append("<Method value=\"");
            sb.append(am.toSaveString());
            sb.append("\" />\n");
        }
        for (AvatarSignal as : this.mySignals) {
            sb.append("<Signal value=\"");
            sb.append(as.toString());
            sb.append("\" attached=\"");
            sb.append(as.attachedToARelation);
            sb.append("\" />\n");
        }
        if (hasGlobalCode()) {
            for (int i = 0; i < globalCode.length; i++) {
                sb.append("<globalCode value=\"");
                sb.append(GTURTLEModeling.transformString(globalCode[i]));
                sb.append("\" />\n");
            }
        }
        sb.append("</extraparam>\n");
        return new String(sb);
    }

    @Override
    public void loadExtraParam(NodeList nl, int decX, int decY, int decId) throws MalformedModelingException {

        String s;
        String tmpGlobalCode = "";

        try {
            NodeList nli;
            Node n1, n2;
            Element elt;
            int access, type;
            String typeOther;
            String id, valueAtt;
            String method;
            String signal;
            AvatarMethod am;
            AvatarSignal as;
            boolean implementation = false;
            String crypt;
            String attached;
            //boolean mustAddCryptoFunctions = false;


            //
            //

            //TraceManager.addDev("LEP Begin Interface  = " + this + " trace=");
            //Thread.currentThread().dumpStack();

            for (int i = 0; i < nl.getLength(); i++) {
                n1 = nl.item(i);
                //
                if (n1.getNodeType() == Node.ELEMENT_NODE) {
                    nli = n1.getChildNodes();
                    for (int j = 0; j < nli.getLength(); j++) {
                        n2 = nli.item(j);
                        //
                        if (n2.getNodeType() == Node.ELEMENT_NODE) {
                            elt = (Element) n2;
                            if (elt.getTagName().equals("CryptoBlock")) {
                                crypt = elt.getAttribute("value");
                                if (crypt.compareTo("true") == 0) {

                                }
                            }
                            if (elt.getTagName().equals("Attribute")) {
                                //
                                access = Integer.decode(elt.getAttribute("access")).intValue();
                                type = Integer.decode(elt.getAttribute("type")).intValue();
                                try {
                                    typeOther = elt.getAttribute("typeOther");
                                } catch (Exception e) {
                                    typeOther = "";
                                }
                                id = elt.getAttribute("id");
                                valueAtt = elt.getAttribute("value");

                                if (valueAtt.equals("null")) {
                                    valueAtt = "";
                                }
                                if ((TAttribute.isAValidId(id, false, false, false)) && (TAttribute.isAValidInitialValue(type, valueAtt))) {
                                    //TraceManager.addDev("Adding attribute " + id + " typeOther=" + typeOther);
                                    if (type == TAttribute.NATURAL) {
                                        type = TAttribute.INTEGER;
                                    }
                                    TAttribute ta = new TAttribute(access, id, valueAtt, type, typeOther);
                                    ta.isAvatar = true;
                                    this.myAttributes.add(ta);
                                }
                            }

                            if (elt.getTagName().equals("Method")) {
                                //
                                method = elt.getAttribute("value");

                                if (method.equals("null")) {
                                    method = "";
                                }
                                if (method.startsWith("$")) {
                                    implementation = true;
                                    method = method.substring(1, method.length());
                                } else {
                                    implementation = false;
                                }

                                //TraceManager.addDev("Method = " + method + ". Starting with aencrypt?");
                                if (method.startsWith("bool verifyMAC(")) {


                                    //TraceManager.addDev("Add crypto methods");
                                    //addCryptoElements();
                                }

                                am = AvatarMethod.isAValidMethod(method);
                                if (am != null) {
                                    //TraceManager.addDev("Setting to " + implementation + " the implementation of " + am);
                                    am.setImplementationProvided(implementation);
                                    //addMethodIfApplicable(am);
                                    this.myMethods.add(am);
                                }
                            }
                            if (elt.getTagName().equals("Signal")) {
                                //
                                signal = elt.getAttribute("value");
                                attached = elt.getAttribute("attached");

                                if (signal.equals("null")) {
                                    signal = "";
                                }
                                as = AvatarSignal.isAValidSignal(signal);
                                if (as != null) {
                                    this.mySignals.add(as);
                                    if (attached != null) {
                                        as.attachedToARelation = (attached.compareTo("true") == 0);
                                    }
                                } else {
                                    TraceManager.addDev("Invalid signal:" + signal);
                                }
                            }
                            if (elt.getTagName().equals("globalCode")) {
                                //
                                s = elt.getAttribute("value");
                                if (s.equals("null")) {
                                    s = "";
                                }
                                tmpGlobalCode += GTURTLEModeling.decodeString(s) + "\n";
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            throw new MalformedModelingException();
        }



        if (tmpGlobalCode.trim().length() == 0) {
            globalCode = null;
        } else {
            globalCode = Conversion.wrapText(tmpGlobalCode);
        }

        //TraceManager.addDev("LEP End Block  = " + this);
    }



    public String getInterfaceName() {
        return value;
    }
    
 
    
    public boolean hasGlobalCode() {
        if (globalCode == null) {
            return false;
        }

        if (globalCode.length == 0) {
            return false;
        }

        String tmp;
        for (int i = 0; i < globalCode.length; i++) {
            tmp = globalCode[i].trim();
            if (tmp.length() > 0) {
                if (!(tmp.equals("\n"))) {
                    return true;
                }
            }
        }

        return false;
    }

    public String getGlobalCode() {
        if (globalCode == null) {
            return null;
        }
        String ret = "";
        for (int i = 0; i < globalCode.length; i++) {
            ret += globalCode[i] + "\n";
        }
        return ret;
    }

    @Override
    public void hasBeenResized() {
        for (int i = 0; i < nbInternalTGComponent; i++) {
            if (tgcomponent[i] instanceof AvatarBDInterface) {
                tgcomponent[i].resizeWithFather();
            } else if (tgcomponent[i] instanceof AvatarBDLibraryFunction) {
                tgcomponent[i].resizeWithFather();
            }
        }

        if (getFather() != null) {
            resizeWithFather();
        }

    }

    @Override
    public void resizeWithFather() {
        if ((father != null) && (father instanceof AvatarBDInterface)) {
            // Too large to fit in the father? -> resize it!
            resizeToFatherSize();

            setCdRectangle(0, father.getWidth() - getWidth(), 0, father.getHeight() - getHeight());
            setMoveCd(x, y);
        }
    }

    public List<AvatarBDInterface> getInterfaceList() {
        List<AvatarBDInterface> list = new LinkedList<AvatarBDInterface>();
        for (int i = 0; i < nbInternalTGComponent; i++) {
            if (tgcomponent[i] instanceof AvatarBDInterface) {
                list.add((AvatarBDInterface) (tgcomponent[i]));
            }
        }
        return list;
    }

    public List<AvatarBDInterface> getFullInterfaceList() {
        List<AvatarBDInterface> list = new LinkedList<AvatarBDInterface>();
        for (int i = 0; i < nbInternalTGComponent; i++) {
            if (tgcomponent[i] instanceof AvatarBDInterface) {
                list.add((AvatarBDInterface) (tgcomponent[i]));
                list.addAll(((AvatarBDInterface) tgcomponent[i]).getFullInterfaceList());
            }
        }
        return list;
    }

    public List<AvatarBDLibraryFunction> getFullLibraryFunctionList() {
        List<AvatarBDLibraryFunction> list = new LinkedList<AvatarBDLibraryFunction>();
        for (int i = 0; i < nbInternalTGComponent; i++) {
            if (this.tgcomponent[i] instanceof AvatarBDLibraryFunction)
                list.add((AvatarBDLibraryFunction) this.tgcomponent[i]);
            else if (this.tgcomponent[i] instanceof AvatarBDInterface)
                list.addAll(((AvatarBDInterface) this.tgcomponent[i]).getFullLibraryFunctionList());
        }

        return list;
    }

    public boolean hasInternalInterfaceWithName(String name) {
        List<AvatarBDInterface> list = getFullInterfaceList();
        for (AvatarBDInterface b : list) {
            if (b.getValue().compareTo(name) == 0) {
                return true;
            }
        }
	/* List<AvatarBDLibraryFunction> llist = getFullLibraryFunctionList();
        for (AvatarBDLibraryFunction b : llist) {
            if (b.getFunctionName().compareTo(name) == 0) {
                return true;
            }
	    }*/

        return false;
    }

    @Override
    public int getDefaultConnector() {
        return TGComponentManager.AVATARBD_PORT_CONNECTOR;
    }

    public List<TAttribute> getAttributeList() {
        return this.myAttributes;
    }

    public TAttribute getAttributeByName(String _name) {
        for (TAttribute a : this.myAttributes)
            if (a.getId().compareTo(_name) == 0)
                return a;
        return null;
    }

    public void addAttribute(TAttribute ta) {
        this.myAttributes.add(ta);
    }

    public List<AvatarMethod> getMethodList() {
        return this.myMethods;
    }

    public List<AvatarSignal> getSignalList() {
        return this.mySignals;
    }

    public List<AvatarSignal> getOutSignalList() {
        List<AvatarSignal> v = new LinkedList<AvatarSignal>();
        for (AvatarSignal s : this.mySignals)
            if (s.getInOut() == AvatarSignal.OUT)
                v.add(s);
        return v;
    }

    public List<AvatarSignal> getInSignalList() {
        List<AvatarSignal> v = new LinkedList<AvatarSignal>();
        for (AvatarSignal s : this.mySignals)
            if (s.getInOut() == AvatarSignal.IN)
                v.add(s);
        return v;
    }

    public List<AvatarMethod> getAllMethodList() {
        if (getFather() == null) {
            return this.myMethods;
        }

        List<AvatarMethod> v = new LinkedList<AvatarMethod>();
        v.addAll(this.myMethods);
        v.addAll(((AvatarBDInterface) getFather()).getAllMethodList());
        return v;
    }

    public List<AvatarSignal> getAllSignalList() {
        if (getFather() == null) {
            return this.mySignals;
        }

        List<AvatarSignal> v = new LinkedList<AvatarSignal>();
        v.addAll(this.mySignals);
        v.addAll(((AvatarBDInterface) getFather()).getAllSignalList());
        return v;
    }

    public List<String> getAllTimerList() {
        List<String> v = new LinkedList<String>();

        for (TAttribute a : this.myAttributes)
            if (a.getType() == TAttribute.TIMER)
                v.add(a.getId());
        return v;
    }

    public AvatarSignal getAvatarSignalFromName(String _name) {
        for (AvatarSignal as : this.mySignals)
            if (as.getId().compareTo(_name) == 0)
                return as;
        return null;
    }

    public List<AvatarSignal> getListOfAvailableSignals() {
        return ((AvatarBDPanel) (tdp)).getListOfAvailableSignals(this);
    }

    public List<AvatarSignal> getListOfAvailableOutSignals() {
        return ((AvatarBDPanel) (tdp)).getListOfAvailableOutSignals(this);
    }

    public List<AvatarSignal> getListOfAvailableInSignals() {
        return ((AvatarBDPanel) (tdp)).getListOfAvailableInSignals(this);
    }

    // _id may contain the full signal
    public AvatarSignal getSignalNameBySignalDef(String _id) {
        int index0 = _id.indexOf('(');
        if (index0 > -1) {
            _id = _id.substring(0, index0);
        }
        _id = _id.trim();
        //TraceManager.addDev("Searching for signal with id=" + _id);
        for (AvatarSignal as : this.mySignals) {
            //	
            if (as.getId().compareTo(_id) == 0)
                return as;
        }
        //TraceManager.addDev("Not found");
        return null;
    }

    public AvatarSignal getAvatarSignalFromFullName(String _id) {
        if (_id.startsWith("in ")) {
            return getSignalNameBySignalDef(_id.substring(3, _id.length()).trim());
        }

        if (_id.startsWith("out ")) {
            return getSignalNameBySignalDef(_id.substring(4, _id.length()).trim());
        }
        return null;
    }

    public AvatarSMDPanel getAvatarSMDPanel() {
        return ((AvatarDesignPanel) (tdp.tp)).getAvatarSMDPanel(getInterfaceName());
    }



    private void removeMethodIfApplicable(String methodString) {
        Iterator<AvatarMethod> iterator = this.myMethods.iterator();
        while (iterator.hasNext()) {
            AvatarMethod am = iterator.next();
            // TODO: replace by a more OO way...
            if (am.toString().equals(methodString)) {
                iterator.remove();
                break;
            }
        }
    }

    public void addMethodIfApplicable(String methodString) {
        for (AvatarMethod am : this.myMethods)
            // TODO: replace by a more OO way...
            if (am.toString().equals(methodString))
                return;

        AvatarMethod am = AvatarMethod.isAValidMethod(methodString);
        if (am != null)
            this.myMethods.add(am);
    }

    public boolean hasDefinitions() {
        return ((this.myAttributes.size() + this.myMethods.size() + this.mySignals.size() + nbInternalTGComponent) > 0);
    }

    // Main Tree

    public int getChildCount() {
        //TraceManager.addDev("Counting childs!");
        return this.myAttributes.size() + this.myMethods.size() + this.mySignals.size() + nbInternalTGComponent;
    }

    public Object getChild(int index) {

        int sa = nbInternalTGComponent;

        if (sa > index) {
            return tgcomponent[index];
        }

        index = index - nbInternalTGComponent;
        sa = this.myAttributes.size();
        //      TraceManager.addDev("index = " + index + " sa=" + sa);
        if (sa <= index) {
            index = index - sa;
            sa = this.myMethods.size();
            if (sa <= index) {
                return this.mySignals.get(index - sa);
            } else {
                return this.myMethods.get(index);
            }
        }

        return this.myAttributes.get(index);
    }

    public int getIndexOfChild(Object child) {
        if (child instanceof AvatarBDInterface) {
            for (int i = 0; i < nbInternalTGComponent; i++) {
                if (tgcomponent[i] == child) {
                    return i;
                }
            }
        }

        if (child instanceof TAttribute) {
            return this.myAttributes.indexOf(child) + nbInternalTGComponent;
        }

        if (child instanceof AvatarMethod) {
            return this.myMethods.indexOf(child) + this.myAttributes.size() + nbInternalTGComponent;
        }

        if (child instanceof AvatarSignal) {
            return this.mySignals.indexOf(child) + this.myAttributes.size() + this.myMethods.size() + nbInternalTGComponent;
        }

        return -1;
    }

    @Override
    public ImageIcon getImageIcon() {
        return myImageIcon;
    }

    public void resetConfidentialityOfAttributes() {
        for (TAttribute a : this.myAttributes)
            a.setConfidentialityVerification(TAttribute.NOT_VERIFIED);
    }

    public String getOwnerName() {
        return this.getInterfaceName();
    }

    @Override
    public String toString() {
        return "Interface: " + getValue();
    }

    public String getAttributes() {
        String attr = "";
        for (TAttribute a : myAttributes) {
            attr += a.toAvatarString() + "\n";
        }
        for (AvatarMethod m : myMethods) {
            attr += m.toString() + "\n";
        }
        for (AvatarSignal s : mySignals) {
            attr += s.toString() + "\n";
        }
        return attr;
    }
}