public void iterateThruContext(String ctxPath, TreeNodeHandler2 handler) {
      String[] path = ctxPath.split("/");
      final String filePath = "/" + path[1];
      int startWith = filePath.startsWith(ContextPath.FILE_CTX_PRX) ? 2 : 1;
      if (startWith == 1) {
        return;
      }

      TreeNode cycled = null;
      int cnt = 0;
      boolean ret = true;
      for (int i = 2; i < path.length && ret; i++) {
        String encodedName = "/" + path[i];
        if (i == 2) {
          cycled = findChildByEncodedName(encodedName, filePath);
        } else {
          cycled = cycled.findChildByEncodedName(encodedName);
        }

        if (cycled != null) {
          ret = handler.handleNode(cnt++, cycled);
        } else {
          // todo - ctx path looks not valid, handle it?
          return;
        }
      }
    }
  public boolean setContextPathAttr(String startCtxPath, String attrName, String value) {
    String[] path = startCtxPath.split("/");
    int startWith = ("/" + path[1]).startsWith(ContextPath.FILE_CTX_PRX) ? 2 : 1;

    TreeNode cycled = root;
    for (int i = startWith; i < path.length; i++) {
      String encodedName = "/" + path[i];
      cycled = cycled.findChildByEncodedName(encodedName);
      if (cycled == null) {
        return false;
      }
    }

    TreeNodeImpl nodeImpl = (TreeNodeImpl) cycled;
    int i = 0;
    for (; i < nodeImpl.extAttr.length; i++) {
      String _attrName = decodeAttrName(nodeImpl.extAttr[i]);
      if (_attrName.equals(attrName)) {
        // replace existing attribute with new one
        nodeImpl.extAttr[i] = encodeAttrValue(attrName, value);
        return true;
      }
    }
    nodeImpl.extAttr = increaseArrayByOne(nodeImpl.extAttr);
    // replace existing attribute with new one
    nodeImpl.extAttr[i] = encodeAttrValue(attrName, value);
    return true;
  }
  private void addCtxValue(TreeNode cycled, String[] pathParts, String value) {
    boolean pathCreated = false;
    for (int i = 2 + 1; i < pathParts.length; i++) {
      String encodedName = "/" + pathParts[i];
      TreeNode child = cycled.findChildByEncodedName(encodedName);
      if (child == null) {
        int type = ContextPathUtil.prefix2type(encodedName.substring(0, 4));
        cycled = cycled.addNode(type, encodedName);
        pathCreated = true;
      } else {
        cycled = child;
      }
    }

    if (pathCreated) {
      entryCounter++;
    }
    if (value != null) {
      cycled.addValue(value);
      modCount++;
    } else {
      // check whether the path was really created
      modCount = (pathCreated) ? modCount + 1 : modCount;
    }
  }
  @NotNull
  public ContextItem[] findCtxItems(String startCtxPath, String name) {
    String[] path = startCtxPath.split("/");
    int startWith = ("/" + path[1]).startsWith(ContextPath.FILE_CTX_PRX) ? 2 : 1;

    TreeNode cycled = root;
    for (int i = startWith; i < path.length; i++) {
      String encodedName = "/" + path[i];
      cycled = cycled.findChildByEncodedName(encodedName);
      if (cycled == null) {
        return new ContextItem[0];
      }
    }

    List<ContextItem> out = new ArrayList<ContextItem>();
    TreeNode[] children =
        name == null
            ? cycled.getChildren().toArray(new TreeNode[0])
            : cycled.findChildrenBySuffix(name);
    for (TreeNode n : children) {
      // todo -- revise to replace using value directly with a TreeNode instance
      out.add(new ContextItemImpl(n.getPath(), n.getValue()));
    }

    return out.toArray(new ContextItem[out.size()]);
  }
  public TreeNode[] findNodeInRelContext(String startCtxPath, String name) {
    String[] path = startCtxPath.split("/");

    TreeNode cycled = root;
    for (int i = 1; i < path.length; i++) {
      String encodedName = "/" + path[i];
      cycled = cycled.findChildByEncodedName(encodedName);
      if (cycled == null) {
        return new TreeNode[0];
      }
    }

    return cycled.findChildrenBySuffix(name);
  }
  private boolean updateCtxValue(TreeNode cycled, String[] pathParts, String value) {
    for (int i = 2 + 1; i < pathParts.length; i++) {
      String encodedName = "/" + pathParts[i];
      TreeNode child = cycled.findChildByEncodedName(encodedName);
      if (child == null) {
        return false;
      } else {
        cycled = child;
      }
    }

    cycled.addValue(value);
    return true;
  }
  public String getContextPathValue(String ctxPath) {
    // todo -- replace split("/") with Pattern.split("/")
    String[] path = ctxPath.split("/");

    int startWith = ("/" + path[1]).startsWith(ContextPath.FILE_CTX_PRX) ? 2 : 1;
    if (startWith == path.length) {
      FileEntitiesHolder hld = files.get(path[1].substring(6));
      if (hld != null) {
        return hld.value; // Long.toString(hld.timeStamp); //
      }

      return null;
    }

    // expected: startWith == 2
    String filePath = path[1].substring(6);

    // find top nodes the specified name
    // "/" + path[2]
    String encodedName = "/" + path[2];
    String name = path[2].substring(6);
    List<TreeNode> addTo = new ArrayList<TreeNode>();
    root.findChildrenBySuffix(name, addTo);

    for (TreeNode node : addTo) {
      // find among top nodes the one which belongs to the correct file
      final TreeNodeTop top = (TreeNodeTop) node;
      if (encodedName.equals(top.encodedName) && filePath.equals(top.owner.filePath)) {
        // the found top node is considered as a root of target hierarhy
        TreeNode cycled = node;
        for (int i = startWith + 1; i < path.length; i++) {
          encodedName = "/" + path[i];
          cycled = cycled.findChildByEncodedName(encodedName);
          if (cycled == null) {
            return null;
          }
        }

        return cycled.getValue();
      } else {
        // todo -- investige the case
        int hh = 0;
      }
    }

    return null;
  }
  public boolean remove(String ctxPath) {
    String[] path = ctxPath.split("/");

    boolean result = false;
    // validate root context
    if (!("/" + path[1]).startsWith(ContextPath.FILE_CTX_PRX)) {
      throw new ValidationException("Broken Context Path occurred: FILE CTX Path must be first!");
    } else {
      switch (path.length) {
        case 0:
        case 1:
          throw new ValidationException("Broken Context Path occurred");
        case 2: // remove the file and all its children
          String fileName = path[1].substring(6);
          FileEntitiesHolder fileHolder = files.remove(fileName);
          if (fileHolder != null) {
            fileHolder.removeChildren();
            result = true;
          }
          break;
        default:
          TreeNode parent = root;
          TreeNode target = null;
          int i = 2;
          while (true) {
            target = parent.findChildByEncodedName("/" + path[i]);
            if (++i < path.length && target != null) {
              parent = target;
              target = null;
            } else {
              break;
            }
          }

          if (target != null) {
            result = parent.removeNodeByEncodedName(target.getName());
          } else {
            // todo -- handle internal error
          }
          break;
      }
    }

    // NOTE: do not simplify! modCOunter should be incremented!
    return result ? ++modCount > 0 : false;
  }
 public void findNodesInContextCommon(
     String startCtxPath, String name, @NotNull TreeNode.TreeNodeHandler handler) {
   if (startCtxPath != null) {
     String[] path = startCtxPath.split("/");
     int startWith = ("/" + path[1]).startsWith(ContextPath.FILE_CTX_PRX) ? 2 : 1;
     TreeNode cycled = root;
     for (int i = startWith; i < path.length; i++) {
       String encodedName = "/" + path[i];
       cycled = cycled.findChildByEncodedName(encodedName);
       if (cycled == null) {
         return; // new TreeNode[0];
       }
     }
     cycled.iterateOverChildrenWithSuffix(name, handler);
   } else {
     root.iterateOverChildrenWithSuffix(name, handler);
   }
 }
  public void iterateOverChildren(String ctxPath, IndexEntriesWalkerInterruptable iterator) {
    String[] path = ctxPath.split("/");
    int startWith = ("/" + path[1]).startsWith(ContextPath.FILE_CTX_PRX) ? 2 : 1;

    TreeNode cycled = root;
    for (int i = startWith; i < path.length; i++) {
      String encodedName = "/" + path[i];
      cycled = cycled.findChildByEncodedName(encodedName);
      if (cycled == null) {
        return;
      }
    }

    for (List<TreeNodeImpl> siblings : ((TreeNodeImpl) cycled).childs.values()) {
      for (TreeNodeImpl n : siblings) {
        if (!iterator.process(n.getPath(), n.value)) {
          return;
        }
      }
    }
  }
  public String _getContextPathValue(String ctxPath) {
    String[] path = ctxPath.split("/");

    int startWith = ("/" + path[1]).startsWith(ContextPath.FILE_CTX_PRX) ? 2 : 1;
    if (startWith == path.length) {
      FileEntitiesHolder hld = files.get(path[1].substring(6));
      if (hld != null) {
        return hld.value; // Long.toString(hld.timeStamp); //
      }

      return null;
    }

    TreeNode cycled = root;
    //        List<TreeNode> addTo = new ArrayList<TreeNode>();
    for (int i = startWith; i < path.length; i++) {
      String encodedName = "/" + path[i];
      /*
      todo - should be implemented along with fixing of the addContextPath
                  cycled.findChildByEncodedName(encodedName, addTo);
                  switch(addTo.size()){
                      case 0: return null;
                      case 1:
                          cycled = addTo.get(0);
                          break;
                      default:
                          cycled = addTo.get(0);
                          break;
                  }

                  addTo.clear();
      */
      cycled = cycled.findChildByEncodedName(encodedName);
      if (cycled == null) {
        return null;
      }
    }

    return cycled.getValue();
  }
  public String getContextPathAttr(String startCtxPath, String attrName) {
    String[] path = startCtxPath.split("/");
    int startWith = ("/" + path[1]).startsWith(ContextPath.FILE_CTX_PRX) ? 2 : 1;

    TreeNode cycled = root;
    for (int i = startWith; i < path.length; i++) {
      String encodedName = "/" + path[i];
      cycled = cycled.findChildByEncodedName(encodedName);
      if (cycled == null) {
        return null;
      }
    }

    TreeNodeImpl nodeImpl = (TreeNodeImpl) cycled;
    int i = 0;
    for (; i < nodeImpl.extAttr.length; i++) {
      String _attrName = decodeAttrName(nodeImpl.extAttr[i]);
      if (_attrName.equals(attrName)) {
        // replace existing attribute with new one
        return decodeAttrValue(nodeImpl.extAttr[i]);
      }
    }
    return null;
  }
  public void searchContextTree_DownUp(
      String startCtxPath, String name, int refType, TreeNodeHandler handler) {
    String[] path = startCtxPath.split("/");

    int _1st_ctxType = -1;
    int startWith = ("/" + path[1]).startsWith(ContextPath.FILE_CTX_PRX) ? 2 : 1;
    List<TreeNode> out = new ArrayList<TreeNode>();

    TreeNode cycled = root;
    for (int i = startWith; i < path.length; i++) {
      String encodedName = "/" + path[i];
      int ctxType = ContextPathUtil.prefix2type(encodedName.substring(0, 4));
      if (i == startWith) {
        // save the type of the first context
        _1st_ctxType = ctxType;
      }

      cycled = cycled.findChildByEncodedName(encodedName);
      if (cycled == null) {
        // todo -- is it suggested?
        break;
      } else {
        if (i == path.length - 1) {
          // check type of the last context
          switch (refType) {
            case ContextPath.NESTED_CALL:
              // search for the name in the context only
              for (TreeNode d : cycled.findChildrenBySuffix(name)) {
                handler.handleNode(d);
              }
              return;
            default:
              switch (ctxType) {
                case ContextPath.COLUMN_DEF:
                case ContextPath.RECORD_ITEM:
                case ContextPath.VARIABLE_DECL:
                case ContextPath.ARGUMENT:
                case ContextPath.REF_CURSOR:
                  // skip search in the context
                  // todo -- more types expected
                  continue;
                default:
                  break;
              }
          }
        } else {
          // intermediate context, add to list
        }

        out.add(cycled);
      }
    }

    for (int i = out.size() - 1; i >= 0; i--) {
      TreeNode n = out.get(i);
      for (TreeNode foundNode : n.findChildrenBySuffix(name)) {
        if (handler.handleNode(foundNode)) {
          // iteration terminated by listener
          return;
        }
      }

      //            switch(n.getType()){
      //                case ContextPath.CURSOR_DECL:
      //                    // Cursor decl: closed scope
      //                    return;
      //            }
    }

    if (_1st_ctxType == ContextPath.PACKAGE_BODY) {
      // search package spec for name
      String spec =
          ContextPath.PACKAGE_SPEC_PRX + path[startWith].substring(3, path[startWith].length());
      for (TreeNode pks : findNodeInRelContext(spec, name)) { // findInContext2(spec, name)) {
        if (handler.handleNode(pks)) {
          // iteration terminated by listener
          return;
        }
      }
    }

    switch (refType) {
      case ContextPath.FUNC_CALL:
      case ContextPath.PROC_CALL:
      case ContextPath.TABLE_REF:
      case ContextPath.TYPE_REF:
      case ContextPath.GENERIC_NAME_REF: // package name (coming from sql code)
      case ContextPath.PLSQL_NAME_REF: // package name (coming from pl/sql code)
        // todo -- do we need to limit target ref types?
        // search in the root context
        for (TreeNode d : findNodeInRootContext(name)) {
          if (handler.handleNode(d)) {
            // iteration terminated by listener
            return;
          }
        }
        break;
    }
  }
  //  /FL!..$ota_flow_manager_pkg.pks/PS!..$ota_flow_manager_pkg/Va!..$pc_bs_15m_dflt [Value]
  // 1|INTEGER
  public void _addContextPath(String ctxPath, String value) {
    String[] path = ctxPath.split("/");

    // validate root context
    if (!("/" + path[1]).startsWith(ContextPath.FILE_CTX_PRX) || ctxPath.indexOf(' ') != -1) {
      throw new ValidationException("Broken Context Path occurred: FILE CTX Path must be first!");
    } else {
      switch (path.length) {
        case 0:
        case 1:
          throw new ValidationException("Broken Context Path occurred");
        case 2: // load file attributes
          String fileName = path[1].substring(6);
          FileEntitiesHolder fileHolder = files.get(fileName);
          if (fileHolder == null) {
            fileHolder = new FileEntitiesHolder(fileName);
            files.put(fileName, fileHolder);
          }
          value = (value == null || value.length() == 0) ? "" : value;
          fileHolder.value = value;
          return;
        default:
          break;
      }
    }

    TreeNode cycled = root;
    boolean pathCreated = false;
    for (int i = 2; i < path.length; i++) {
      String encodedName = "/" + path[i];
      int type = ContextPathUtil.prefix2type(encodedName.substring(0, 4));
      TreeNode child = cycled.findChildByEncodedName(encodedName);
      if (child == null) {
        if (i == 2) {
          // add node level 1 -
          cycled = addTopNode(root, type, encodedName, path[1].substring(6));
        } else {
          cycled = cycled.addNode(type, encodedName);
        }
        pathCreated = true;
      } else {
        cycled = child;
      }
    }

    /*      todo -- entryCounter not correct any longer, FIXME
            if (cycled.getValue() == null) {
                entryCounter++;
            }
            cycled.addValue(value == null ? "" : value);
    */
    if (pathCreated) {
      entryCounter++;
    }
    if (value != null) {
      cycled.addValue(value);
      modCount++;
    } else {
      // check whether the path was really created
      modCount = (pathCreated) ? modCount + 1 : modCount;
    }

    // log adding entry
    println("[Path] " + ctxPath + " [Value] " + value);
  }