private FixedCoords getFixedCoords(Element shape, int width, int height, String suffix) {
      if (suffix == null) suffix = "";
      // parse the coordinates and check if they are fixed or reverse fixed
      String val = shape.getAttribute(ATR_X + suffix);
      int x, y, fixedX = 0, fixedY = 0;
      if (val.endsWith(VAL_RF)) {
        x = width;
        fixedX = x - Integer.parseInt(val.substring(0, val.length() - 2));
      } else if (val.endsWith(VAL_F)) {
        x = Integer.parseInt(val.substring(0, val.length() - 1));
        fixedX = -1;
      } else {
        x = Integer.parseInt(val);
      }
      val = shape.getAttribute(ATR_Y + suffix);
      if (val.endsWith(VAL_RF)) {
        y = height;
        fixedY = y - Integer.parseInt(val.substring(0, val.length() - 2));
      } else if (val.endsWith(VAL_F)) {
        y = Integer.parseInt(val.substring(0, val.length() - 1));
        fixedY = -1;
      } else {
        y = Integer.parseInt(val);
      }

      return new FixedCoords(x, fixedX, y, fixedY);
    }
 private Dim getDim(Element shape) {
   return new Dim(
       Integer.parseInt(shape.getAttribute(ATR_X)),
       Integer.parseInt(shape.getAttribute(ATR_Y)),
       Integer.parseInt(shape.getAttribute(ATR_WIDTH)),
       Integer.parseInt(shape.getAttribute(ATR_HEIGHT)));
 }
 private Lineprops getLineProps(Element shape) {
   return new Lineprops(
       shape.hasAttribute(ATR_STROKE)
           ? Float.parseFloat(shape.getAttribute(ATR_STROKE))
           : IMPLIED_STROKE,
       shape.hasAttribute(ATR_LINETYPE)
           ? Float.parseFloat(shape.getAttribute(ATR_LINETYPE))
           : IMPLIED_LINE);
 }
    private Text makeText(Element textNode, ClassGraphics graphics) {
      String str = textNode.getAttribute(ATR_STRING);

      String fontName = textNode.getAttribute(ATR_FONTNAME);
      int fontStyle = Integer.parseInt(textNode.getAttribute(ATR_FONTSTYLE));
      int fontSize = Integer.parseInt(textNode.getAttribute(ATR_FONTSIZE));

      Font font = new Font(fontName, fontStyle, fontSize);

      FixedCoords fc =
          getFixedCoords(textNode, graphics.getBoundWidth(), graphics.getBoundHeight(), null);

      Text newText = new Text(fc.x, fc.y, font, getColor(textNode), str, isShapeFixed(textNode));
      newText.setFixedX(fc.fx);
      newText.setFixedY(fc.fy);

      return newText;
    }
    private Color getColor(Element shape) {
      Color color;
      if (shape.hasAttribute(ATR_COLOUR)) {
        String s = shape.getAttribute(ATR_COLOUR);
        if (s.indexOf(',') > -1) {
          String[] rgb = s.split(",");
          color =
              new Color(
                  Integer.parseInt(rgb[0]), Integer.parseInt(rgb[1]), Integer.parseInt(rgb[2]));
        } else {
          color = new Color(Integer.parseInt(s));
        }
      } else color = IMPLIED_COLOR;

      if (shape.hasAttribute(ATR_TRANSPARENCY)) {
        int alpha = Integer.parseInt(shape.getAttribute(ATR_TRANSPARENCY));
        if (alpha < 255) return new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
      }

      return color;
    }
    private ClassGraphics parse(Element grNode /*, boolean isRelation*/) {
      ClassGraphics newGraphics = new ClassGraphics();
      newGraphics.setShowFields(Boolean.parseBoolean(grNode.getAttribute(ATR_SHOW_FIELDS)));
      // newGraphics.setRelation( isRelation );

      NodeList list = grNode.getChildNodes();
      for (int k = 0; k < list.getLength(); k++) {
        if (list.item(k).getNodeType() != Node.ELEMENT_NODE) continue;
        Element node = (Element) list.item(k);
        String nodeName = node.getNodeName();

        Shape shape = null;
        if (EL_BOUNDS.equals(nodeName)) {
          Dim dim = getDim(node);
          newGraphics.setBounds(dim.x, dim.y, dim.width, dim.height);
          continue;
        } else if (EL_LINE.equals(nodeName)) {

          shape = makeLine(node, newGraphics);

        } else if (EL_RECT.equals(nodeName)) {

          Dim dim = getDim(node);
          Lineprops lp = getLineProps(node);
          shape =
              new Rect(
                  dim.x,
                  dim.y,
                  dim.width,
                  dim.height,
                  getColor(node),
                  isShapeFilled(node),
                  lp.strokeWidth,
                  lp.lineType);

        } else if (EL_OVAL.equals(nodeName)) {

          Dim dim = getDim(node);
          Lineprops lp = getLineProps(node);
          shape =
              new Oval(
                  dim.x,
                  dim.y,
                  dim.width,
                  dim.height,
                  getColor(node),
                  isShapeFilled(node),
                  lp.strokeWidth,
                  lp.lineType);

        } else if (EL_ARC.equals(nodeName)) {

          Dim dim = getDim(node);
          Lineprops lp = getLineProps(node);
          int startAngle = Integer.parseInt(node.getAttribute(ATR_START_ANGLE));
          int arcAngle = Integer.parseInt(node.getAttribute(ATR_ARC_ANGLE));
          shape =
              new Arc(
                  dim.x,
                  dim.y,
                  dim.width,
                  dim.height,
                  startAngle,
                  arcAngle,
                  getColor(node),
                  isShapeFilled(node),
                  lp.strokeWidth,
                  lp.lineType);

        } else if (EL_POLYGON.equals(nodeName)) {
          Lineprops lp = getLineProps(node);

          Polygon polygon =
              new Polygon(getColor(node), isShapeFilled(node), lp.strokeWidth, lp.lineType);

          // points
          NodeList points = node.getElementsByTagName(EL_POINT);
          int pointCount = points.getLength();
          // arrays of polygon points
          int[] xs = new int[pointCount];
          int[] ys = new int[pointCount];
          // arrays of FIXED information about polygon points
          int[] fxs = new int[pointCount];
          int[] fys = new int[pointCount];
          int width = newGraphics.getBoundWidth();
          int height = newGraphics.getBoundHeight();

          for (int j = 0; j < pointCount; j++) {
            FixedCoords fc = getFixedCoords((Element) points.item(j), width, height, null);
            xs[j] = fc.x;
            fxs[j] = fc.fx;
            ys[j] = fc.y;
            fys[j] = fc.fy;
          }

          polygon.setPoints(xs, ys, fxs, fys);
          shape = polygon;

        } else if (EL_IMAGE.equals(nodeName)) {

          Dim dim = getDim(node);
          // image path should be relative to the package xml
          String imgPath = node.getAttribute(ATR_PATH);
          String fullPath = FileFuncs.preparePathOS(getWorkingDir() + imgPath);
          shape = new Image(dim.x, dim.y, fullPath, imgPath, isShapeFixed(node));

        } else if (EL_TEXT.equals(nodeName)) {
          shape = makeText(node, newGraphics);
          /*
           * if (str.equals("*self")) newText.name = "self"; else if
           * (str.equals("*selfWithName")) newText.name = "selfName";
           */
        }

        if (shape != null) newGraphics.addShape(shape);
      }

      return newGraphics;
    }
 private boolean isShapeFixed(Element shape) {
   return Boolean.parseBoolean(shape.getAttribute(ATR_FIXED));
 }
  private void parsePort(PackageClass newClass, Element portNode) {
    String name = portNode.getAttribute(ATR_NAME);
    String type = portNode.getAttribute(ATR_TYPE);
    String x = portNode.getAttribute(ATR_X);
    String y = portNode.getAttribute(ATR_Y);
    String portConnection = portNode.getAttribute(ATR_PORT_CONNECTION);
    String strict = portNode.getAttribute(ATR_STRICT);
    String multi = portNode.getAttribute(ATR_MULTI);

    ClassField cf = newClass.getSpecField(name);

    if (newClass.getComponentType().hasSpec()) {

      if (name.indexOf(".") > -1) {
        // TODO - temporarily do not dig into hierarchy
        int idx = name.indexOf(".");
        String root = name.substring(0, idx);

        if (newClass.getSpecField(root) == null) {
          collector.collectDiagnostic(
              "Field "
                  + root
                  + " in class "
                  + newClass.getName()
                  + " is not declared in the specification, variable "
                  + type
                  + " "
                  + name
                  + " ignored ");
          return;
        }

        newClass.addSpecField(new ClassField(name, type));
      } else if (!TypeUtil.TYPE_THIS.equalsIgnoreCase(name)) {
        if (cf == null) {

          collector.collectDiagnostic(
              "Port "
                  + type
                  + " "
                  + name
                  + " in class "
                  + newClass.getName()
                  + " does not have the corresponding field in the specification");
        } else if (!cf.getType().equals(type)
            // type may be declared as "alias", however cf.getType() returns e.g. "double[]", ignore
            // it
            && !(cf.isAlias() && TypeUtil.TYPE_ALIAS.equals(type))) {

          collector.collectDiagnostic(
              "Port "
                  + type
                  + " "
                  + name
                  + " in class "
                  + newClass.getName()
                  + " does not match the field declared in the specification: "
                  + cf.getType()
                  + " "
                  + cf.getName());
        }
      }
    }

    Port newPort =
        new Port(
            name,
            type,
            Integer.parseInt(x),
            Integer.parseInt(y),
            portConnection,
            Boolean.parseBoolean(strict),
            Boolean.parseBoolean(multi));

    if (portNode.hasAttribute(ATR_ID)) newPort.setId(portNode.getAttribute(ATR_ID));

    Element gr;
    // open
    if ((gr = getElementByName(portNode, EL_OPEN)) != null
        && (gr = getElementByName(gr, EL_GRAPHICS)) != null) {
      newPort.setOpenGraphics(getGraphicsParser().parse(gr));
    }

    // closed
    if ((gr = getElementByName(portNode, EL_CLOSED)) != null
        && (gr = getElementByName(gr, EL_GRAPHICS)) != null) {
      newPort.setClosedGraphics(getGraphicsParser().parse(gr));
    }

    newClass.addPort(newPort);
  }
  private void parseField(PackageClass newClass, Element fieldNode) {
    String name = fieldNode.getAttribute(ATR_NAME);
    String type = fieldNode.getAttribute(ATR_TYPE);

    ClassField newField;

    if (newClass.getComponentType().hasSpec()) {
      if (name.indexOf(".") > -1) {
        // TODO - temporarily do not dig into hierarchy
        int idx = name.indexOf(".");
        String root = name.substring(0, idx);

        if (newClass.getSpecField(root) == null) {
          collector.collectDiagnostic(
              "Field "
                  + root
                  + " in class "
                  + newClass.getName()
                  + " is not declared in the specification, variable "
                  + type
                  + " "
                  + name
                  + " ignored ");
          return;
        }

        newField = new ClassField(name, type);
        newClass.addSpecField(newField);
      } else {
        newField = newClass.getSpecField(name);

        if (newField == null) {

          collector.collectDiagnostic(
              "Field "
                  + type
                  + " "
                  + name
                  + " in class "
                  + newClass.getName()
                  + " is not declared in the specification");
          return;
        } else if (!newField.getType().equals(type)) {

          collector.collectDiagnostic(
              "Field "
                  + type
                  + " "
                  + name
                  + " in class "
                  + newClass.getName()
                  + " does not match the field declared in the specification: "
                  + newField.getType()
                  + " "
                  + newField.getName());
          return;
        }
      }
    } else {
      newField = new ClassField(name, type);
      newClass.addSpecField(newField);
    }

    newField.setValue(fieldNode.hasAttribute(ATR_VALUE) ? fieldNode.getAttribute(ATR_VALUE) : null);
    newField.setDescription(fieldNode.getAttribute(ATR_DESCRIPTION));
    newField.setHidden(Boolean.parseBoolean(fieldNode.getAttribute(ATR_HIDDEN)));

    String nature = fieldNode.getAttribute(ATR_NATURE);
    if ("input".equals(nature)) newField.setInput(true);
    else if ("goal".equals(nature)) newField.setGoal(true);

    newClass.addField(newField);

    Element gr;
    // known
    if ((gr = getElementByName(fieldNode, EL_KNOWN)) != null
        && (gr = getElementByName(gr, EL_GRAPHICS)) != null) {
      newField.setKnownGraphics(getGraphicsParser().parse(gr));
    }
    // default
    if ((gr = getElementByName(fieldNode, EL_DEFAULT)) != null
        && (gr = getElementByName(gr, EL_GRAPHICS)) != null) {
      newField.setDefaultGraphics(getGraphicsParser().parse(gr));
    }
  }
  private PackageClass parseClass(Element classNode) {
    PackageClass newClass = new PackageClass();
    _package.getClasses().add(newClass);

    newClass.setComponentType(PackageClass.ComponentType.getType(classNode.getAttribute(ATR_TYPE)));
    newClass.setStatic(Boolean.parseBoolean(classNode.getAttribute(ATR_STATIC)));
    newClass.setName(getElementByName(classNode, EL_NAME).getTextContent());
    final String source = getElementStringByName(classNode, EL_FILE);
    if (source != null) {
      newClass.setSource(source);
    }
    newClass.setTarget(getElementStringByName(classNode, EL_EXTENDS));
    newClass.setDescription(getElementByName(classNode, EL_DESCRIPTION).getTextContent());
    newClass.setIcon(getElementByName(classNode, EL_ICON).getTextContent());

    // parse all variables declared in the corresponding specification
    if (newClass.getComponentType().hasSpec()) {
      final String newClassName = newClass.getName();
      try {
        switch (RuntimeProperties.getSpecParserKind()) {
          case REGEXP:
            {
              ClassList classList = new ClassList();
              SpecParser.parseSpecClass(newClassName, getWorkingDir(), classList);
              newClass.setSpecFields(classList.getType(newClassName).getFields());
              break;
            }
          case ANTLR:
            {
              if (specificationLoader == null) {
                specificationLoader =
                    new SpecificationLoader(new PackageSpecSourceProvider(_package), null);
              }
              final AnnotatedClass annotatedClass =
                  specificationLoader.getSpecification(newClassName);
              newClass.setSpecFields(annotatedClass.getFields());
              break;
            }
          default:
            throw new IllegalStateException("Undefined specification language parser");
        }
      } catch (SpecParseException e) {
        final String msg = "Unable to parse the specification of class " + newClassName;
        logger.error(msg, e);
        collector.collectDiagnostic(msg + "\nReason: " + e.getMessage() + "\nLine: " + e.getLine());
      }
    }

    // Graphics
    Element grNode = getElementByName(classNode, EL_GRAPHICS);
    newClass.addGraphics(
        getGraphicsParser().parse(grNode/*, newClass.getComponentType() == ComponentType.REL*/ ));

    Element painter;
    if ((painter = getElementByName(grNode, EL_PAINTER)) != null) {
      newClass.setPainterName(painter.getTextContent());
    }

    // Ports
    NodeList ports = classNode.getElementsByTagName(EL_PORT);
    for (int i = 0; i < ports.getLength(); i++) {
      parsePort(newClass, (Element) ports.item(i));
    }

    // Fields
    NodeList fields = classNode.getElementsByTagName(EL_FIELD);
    for (int i = 0; i < fields.getLength(); i++) {
      parseField(newClass, (Element) fields.item(i));
    }

    return newClass;
  }