@Override
  public VPackage parse() {

    logger.debug("Starting parsing package: " + xmlFile.getAbsolutePath());

    long startParsing = System.currentTimeMillis();

    try {
      Document document = getDocument();
      Element root = document.getDocumentElement();

      _package = new VPackage(xmlFile);

      Node name = root.getElementsByTagName(EL_NAME).item(0);
      _package.setName(name.getTextContent());
      Node descr = root.getElementsByTagName(EL_DESCRIPTION).item(0);
      _package.setDescription(descr.getTextContent());

      NodeList list = root.getElementsByTagName(EL_CLASS);

      boolean initPainters = false;
      for (int i = 0; i < list.getLength(); i++) {
        PackageClass pc = parseClass((Element) list.item(i));
        if (pc.getPainterName() != null) {
          initPainters = true;
        }
      }

      if (initPainters) {
        _package.initPainters();
      }

      logger.info(
          "Parsing the package '{}' finished in {}ms.\n",
          _package.getName(),
          (System.currentTimeMillis() - startParsing));
    } catch (Exception e) {
      collector.collectDiagnostic(e.getMessage(), true);
      if (RuntimeProperties.isLogDebugEnabled()) {
        e.printStackTrace();
      }
    }

    try {
      checkProblems("Error parsing package file " + xmlFile.getName());
    } catch (Exception e) {
      return null;
    }

    return _package;
  }
  public void addPackageClass(PackageClass pClass) {

    Document doc;
    try {
      doc = getDocument();
    } catch (Exception e) {
      e.printStackTrace();
      return;
    }

    String name = pClass.getName();

    // check if such class exists and remove duplicates
    Element rootEl = doc.getDocumentElement();
    NodeList classEls = rootEl.getElementsByTagName(EL_CLASS);
    for (int i = 0; i < classEls.getLength(); i++) {
      Element nameEl = getElementByName((Element) classEls.item(i), EL_NAME);
      if (name.equals(nameEl.getTextContent())) {
        rootEl.removeChild(classEls.item(i));
      }
    }

    Element classNode = doc.createElement(EL_CLASS);
    doc.getDocumentElement().appendChild(classNode);
    classNode.setAttribute(ATR_TYPE, PackageClass.ComponentType.SCHEME.getXmlName());
    classNode.setAttribute(ATR_STATIC, "false");

    Element className = doc.createElement(EL_NAME);
    className.setTextContent(name);
    classNode.appendChild(className);

    Element desrc = doc.createElement(EL_DESCRIPTION);
    desrc.setTextContent(pClass.getDescription());
    classNode.appendChild(desrc);

    Element icon = doc.createElement(EL_ICON);
    icon.setTextContent(pClass.getIcon());
    classNode.appendChild(icon);

    // graphics
    classNode.appendChild(generateGraphicsNode(doc, pClass.getGraphics()));

    // ports
    List<Port> ports = pClass.getPorts();
    if (!ports.isEmpty()) {
      Element portsEl = doc.createElement(EL_PORTS);
      classNode.appendChild(portsEl);

      for (Port port : ports) {
        portsEl.appendChild(generatePortNode(doc, port));
      }
    }

    // fields
    Collection<ClassField> fields = pClass.getFields();
    if (!fields.isEmpty()) {
      Element fieldsEl = doc.createElement(EL_FIELDS);
      classNode.appendChild(fieldsEl);

      for (ClassField cf : fields) {
        fieldsEl.appendChild(generateFieldNode(doc, cf));
      }
    }

    // write
    try {
      writeDocument(doc, new FileOutputStream(xmlFile));
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }
  }
    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 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;
  }