public Map<EdgeLabel, Map<EdgeIndex, Edge>> getOutEdges(
      long receiverId,
      long senderId,
      NidVer oid,
      EnumSet<EdgeType> types,
      boolean queryableOnly,
      Optional<EdgeLabel> labelFilter,
      boolean checkExistenceOfPrivateLabelFilter)
      throws NodeNotFoundException {
    /* Check modifier */
    if (labelFilter.isPresent()) {
      if (labelFilter.get().isPublic() && (!types.contains(EdgeType.publicMod))) {
        throw new IllegalArgumentException(
            "Public label is given and EdgeType.publicMod " + "is missing");
      }
      if ((!labelFilter.get().isPublic()) && (!types.contains(EdgeType.privateMod))) {
        throw new IllegalArgumentException(
            "Private label is given and EdgeType.privateMod" + "is missing");
      }
    }

    /* Check label filter */
    if (checkExistenceOfPrivateLabelFilter
        && (labelFilter.isPresent())
        && (!labelFilter.get().isPublic())) {
      final NodeImpl node = getNodeFromCurrentOrHistorized(receiverId, oid);
      if (node == null) {
        throw new NodeNotFoundException("Node not found");
      }
      final long nodeClassId = node.getNodeSerie().getClassId();
      final NodeClass nodeClass = this.ncApi.getClassById(nodeClassId);
      if (!nodeClass.getEdgeClasses().containsKey(labelFilter.get().getPrivateEdgeIndex()))
        throw new IllegalArgumentException(
            "Given (private) label filter is not declared " + "in class.");
    }

    Map<EdgeLabel, Map<EdgeIndex, EdgeImpl>> outEdgesImpl =
        getOutEdgesImpl(receiverId, senderId, oid, types, queryableOnly);
    Map<EdgeLabel, Map<EdgeIndex, Edge>> outEdges = new HashMap<>();

    for (final Map.Entry<EdgeLabel, Map<EdgeIndex, EdgeImpl>> outEdgesImplEntry :
        outEdgesImpl.entrySet()) {
      final Map<EdgeIndex, Edge> singleEntry = new HashMap<>();
      final EdgeLabel edgeLabel = outEdgesImplEntry.getKey();
      if (labelFilter.isPresent() && (!labelFilter.get().equals(edgeLabel))) {
        /* Wrong label */
        continue;
      }
      outEdges.put(outEdgesImplEntry.getKey(), singleEntry);
      for (final Map.Entry<EdgeIndex, EdgeImpl> entry : outEdgesImplEntry.getValue().entrySet()) {
        final Edge edge = this.edgeUtil.toEdge(entry.getValue());
        singleEntry.put(entry.getKey(), edge);
      }
    }

    return outEdges;
  }
  public Map<EdgeLabel, Map<EdgeIndex, EdgeImpl>> getOutEdgesImpl(
      long receiverId, long senderId, NidVer oid, EnumSet<EdgeType> types, boolean queryableOnly)
      throws NodeNotFoundException {
    if (types.isEmpty()) {
      throw new ExpectableException("Types cannot be empty");
    }
    final NodeImpl node = getNodeFromCurrentOrHistorized(receiverId, oid);
    if (node == null) {
      throw new NodeNotFoundException("Node not found");
    }
    final long nodeClassId = node.getNodeSerie().getClassId();
    final NodeClass nodeClass = this.ncApi.getClassById(nodeClassId);
    final Map<EdgeLabel, Map<EdgeIndex, EdgeImpl>> privateEdges = new HashMap<>();
    for (Map.Entry<EdgeLabel, Map<EdgeIndex, EdgeImpl>> edgesEntry :
        node.getOutEdges().entrySet()) {

      /* Is queryable? */
      final boolean isQueryable;
      if (edgesEntry.getKey().isPublic()) {
        isQueryable = edgesEntry.getKey().isPublicQueryable();
      } else {
        EdgeClass pec = nodeClass.getEdgeClasses().get(edgesEntry.getKey().getPrivateEdgeIndex());
        isQueryable = pec.isQueryable();
      }

      if (queryableOnly && (!isQueryable)) {
        continue;
      }
      final boolean isPublic = edgesEntry.getKey().isPublic();
      final boolean add =
          (isPublic && types.contains(EdgeType.publicMod))
              || (!isPublic && types.contains(EdgeType.privateMod));
      if (add) {
        privateEdges.put(edgesEntry.getKey(), edgesEntry.getValue());
      }
    }
    return privateEdges;
  }
  @Nullable
  public Object getData(
      long receiverId, long senderId, NidVer nidVer, short typeIndex, IDataGetter dataGetter)
      throws NodeNotFoundException {
    final NodeImpl node =
        this.nodes.getByUserId(receiverId).getNode(nidVer.getNid(), nidVer.getVersion(), false);
    if (node == null) {
      throw new NodeNotFoundException("Node not found");
    }
    final long classId = node.getNodeSerie().getClassId();

    final NodeClass nc = this.ncApi.getClassById(classId);
    if (nc == null) {
      throw new IllegalStateException("NodeClass not found");
    }
    final IType type = nc.getType(typeIndex);
    final boolean supports = type.supports(dataGetter);
    if (!supports) {
      throw new ExpectableException("The given data getter is no supported on this type.");
    }
    // ITypeImpl ti = this.typesRegistry.get(type.getRef());
    final Object value = node.getData()[typeIndex];
    return type.getData(dataGetter, value);
  }