private void dijkstraAlgorithm() {
    this.jTextHeap.setText("");
    // check solved
    if (this.alState == StateAlgorithm.SOLVED) return;
    // first time run
    if (this.curVertex == null) {
      this.endVertex.state = State.UNLABELED;
      this.curVertex = this.pnHeap.heap.deleteMin();
      this.curVertex.state = State.SCANNED;
      this.curPos = 0;
    }
    int sz = this.curVertex.outgoingEdges.size();
    if (this.curPos < sz) {
      if (this.curEdge != null) this.curEdge.edgeState = State.UNLABELED;
      this.curEdge = this.curVertex.outgoingEdges.get(this.curPos);
      this.curEdge.edgeState = State.SCANNED;
      Vertex tailOfCurVertex = this.curEdge.getTail();

      if (tailOfCurVertex.state != State.SCANNED) {
        if (tailOfCurVertex.state == State.UNLABELED) {
          // insert a vertex with
          tailOfCurVertex.state = State.LABELED;
          tailOfCurVertex.setPred(this.curVertex);
          tailOfCurVertex.setKey(this.curVertex.getKey() + this.curEdge.getLength());
          this.pnHeap.heap.insertVertex(tailOfCurVertex);
          this.jTextHeap.setText("Insert vertex " + Integer.toString(tailOfCurVertex.getData()));
        } else if (tailOfCurVertex.getKey() > this.curVertex.getKey() + this.curEdge.getLength()) {
          // decrease the key of a vertex with finite key
          tailOfCurVertex.setPred(this.curVertex);
          this.jTextHeap.setText(
              "Decrease key of vertex "
                  + Integer.toString(tailOfCurVertex.getData())
                  + " from "
                  + Integer.toString(tailOfCurVertex.getKey())
                  + " to "
                  + Integer.toString(this.curVertex.getKey() + this.curEdge.getLength()));
          this.pnHeap.heap.decreaseKey(
              this.curVertex.getKey() + this.curEdge.getLength(), tailOfCurVertex);
        }
      }
      // check next outgoing edge
      this.curPos++;
    } else if (!this.pnHeap.heap.isEmpty()) {
      this.curEdge.edgeState = State.UNLABELED;
      this.curVertex = this.pnHeap.heap.deleteMin();
      this.jTextHeap.setText("Delete min vertex " + Integer.toString(this.curVertex.getData()));
      this.curVertex.state = State.SCANNED;
      this.curPos = 0;
    } else this.alState = StateAlgorithm.SOLVED;
    this.pnHeap.repaint();
    this.pnGraph.repaint();
  }
  private void saveMenuItemActionPerformed(
      java.awt.event.ActionEvent evt) { // GEN-FIRST:event_saveMenuItemActionPerformed

    this.jTextStatus.setText("");
    if (this.pnGraph.listEdges.isEmpty() && this.pnGraph.listVertexs.isEmpty()) {
      this.jTextStatus.setText("Empty graph, not save");
      return;
    }
    if (this.jSaveFileChooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
      File file = this.jSaveFileChooser.getSelectedFile();
      try {
        BufferedWriter output = new BufferedWriter(new FileWriter(file));
        try {
          for (Vertex Vertex : this.pnGraph.listVertexs) {
            output.write(
                String.format(
                    "Vertex:%d:%d:%d", Vertex.getData(), Vertex.getX_cor(), Vertex.getY_cor()));
            output.newLine();
          }
          for (Edge edge : this.pnGraph.listEdges) {
            output.write(
                String.format(
                    "Edge:%d:%d:%d",
                    edge.getHead().getData(), edge.getTail().getData(), edge.getLength()));
            output.newLine();
          }
          this.jTextStatus.setText("Save graph successfully");
        } finally {
          output.close();
        }
      } catch (IOException e) {
      }
    }
  } // GEN-LAST:event_saveMenuItemActionPerformed
  private void pnGraphMouseReleased(
      java.awt.event.MouseEvent evt) { // GEN-FIRST:event_pnGraphMouseReleased

    int x = 0;
    int y = 0;
    Vertex vertex = null;
    if (this.drawType != DrawType.NODRAW || this.start || this.end) {
      x = evt.getX() - jGraphPanel.radius / 2;
      y = evt.getY() - jGraphPanel.radius / 2;
      if (x < 0 || y < 0) {
        this.jTextStatus.setText("Invalid position");
        this.drawType = DrawType.NODRAW;
        return;
      }
      vertex = this.pnGraph.checkInVertex(x, y);
      if (vertex != null)
        if (vertex.state != State.LABELED)
          if (this.start) {
            vertex.state = State.LABELED;
            vertex.setKey(0);
            this.startVertex = vertex;
            this.jTextStatus.setText("");
            this.jSolution.append(
                "Starting vertex\t: Vertex " + Integer.toString(vertex.getData()) + "\n");
            this.start = false;
          } else if (this.end) {
            vertex.state = State.LABELED;
            this.endVertex = vertex;
            this.jTextStatus.setText("");
            this.jSolution.append(
                "Ending vertex\t: Vertex " + Integer.toString(vertex.getData()) + "\n");
            this.end = false;
          }
    }

    if (this.drawType == DrawType.VERTEXS) {
      if (vertex != null) {
        this.jTextStatus.setText("Concurred with another vertex");
      } else {
        this.pnGraph.listVertexs.add(new Vertex(x, y, this.numVertexs, -1));
        this.numVertexs++;
      }
    } else if (this.drawType == DrawType.EDGES) {
      if (vertex == null) this.jTextStatus.setText("You must click on exist vertex");
      else if (vertex == this.head) this.jTextStatus.setText("You must choose another vertex");
      else {
        if (draw) {
          this.pnGraph.mDrag = false;
          this.pnGraph.head = null;
          Edge edge = new Edge(this.head, vertex, 10);
          edge.edgeType = this.pnGraph.checkEdge(this.head, vertex);
          if (this.jRandomCheck.isSelected()) {
            Random random = new Random();
            edge.setLength(random.nextInt(20));
          } else
            edge.setLength(
                Integer.parseInt(
                    JOptionPane.showInputDialog(
                        null, "Length of edge", "Edge", JOptionPane.QUESTION_MESSAGE)));
          this.head.outgoingEdges.add(edge);
          vertex.incomingEdges.add(edge);
          this.pnGraph.listEdges.add(edge);
          this.head = null;
          this.jTextStatus.setText("Draw an edge");
          this.draw = false;
        } else {
          this.head = vertex;
          this.pnGraph.head = vertex;
          this.pnGraph.xM = evt.getX();
          this.pnGraph.yM = evt.getY();
          this.pnGraph.mDrag = true;
          this.jTextStatus.setText("Choose tail vertex");
          this.draw = true;
        }
      }
    }
    this.pnGraph.repaint();
  } // GEN-LAST:event_pnGraphMouseReleased