data parser CHANGE when conditions resolving

when-stmt must be resolved before any other data property (leafref,
instance-identifier, must) because it can modify the tree (auto-delete).
diff --git a/src/resolve.c b/src/resolve.c
index f3606c8..2403463 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -1774,7 +1774,7 @@
         /* it was converted to JSON format before, nothing else sensible we can do */
 
     } else {
-        ret = lyp_parse_value(&node, NULL, 1, NULL);
+        ret = lyp_parse_value(&node, NULL, 1);
     }
 
 finish:
@@ -3664,6 +3664,7 @@
             ly_vlog_hide(1);
             LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "When", ((struct lys_node_container *)node->schema)->when->cond);
             ly_vlog_hide(0);
+            node->when_status |= LYD_WHEN_FALSE;
             goto success;
         }
     }
@@ -3694,6 +3695,7 @@
                 ly_vlog_hide(1);
                 LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "When", ((struct lys_node_uses *)parent)->when->cond);
                 ly_vlog_hide(0);
+                node->when_status |= LYD_WHEN_FALSE;
                 goto success;
             }
         }
@@ -3721,6 +3723,7 @@
                 ly_vlog_hide(1);
                 LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
                 ly_vlog_hide(0);
+                node->when_status |= LYD_WHEN_FALSE;
                 goto success;
             }
         }
@@ -3728,10 +3731,9 @@
         parent = lys_parent(parent);
     }
 
-success:
-    /* mark the node as node with resolved when-stmt condition */
-    node->when_status = ~node->when_status;
+    node->when_status |= LYD_WHEN_TRUE;
 
+success:
     return 0;
 }
 
@@ -4186,35 +4188,6 @@
     }
 }
 
-/* logs directly */
-static void
-print_unres_data_item_fail(struct lyd_node *node, enum UNRES_ITEM type)
-{
-    struct lys_node_leaf *sleaf;
-
-    sleaf = (struct lys_node_leaf *)node->schema;
-
-    switch (type) {
-    case UNRES_LEAFREF:
-        LOGVRB("Leafref \"%s\" could not be resolved, it will be attempted later.",
-               sleaf->type.info.lref.path);
-        break;
-    case UNRES_INSTID:
-        LOGVRB("Instance-identifier \"%s\" could not be resolved, it will be attempted later.",
-               ((struct lyd_node_leaf_list *)node)->value_str);
-        break;
-    case UNRES_WHEN:
-        LOGVRB("There was an unsatisfied when condition, evaluation will be attempted later.");
-        break;
-    case UNRES_MUST:
-        LOGVRB("There was an unsatisfied must condition, evaluation will be attempted later.");
-        break;
-    default:
-        LOGINT;
-        break;
-    }
-}
-
 /**
  * @brief Resolve a single unres data item. Logs directly.
  *
@@ -4298,8 +4271,16 @@
     return EXIT_SUCCESS;
 }
 
+/**
+ * @brief add data unres item
+ *
+ * @param[in] unres Unres data structure to use.
+ * @param[in] node Data node to use.
+ *
+ * @return 0 on success, -1 on error.
+ */
 int
-unres_data_addonly(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
+unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
 {
     assert(unres && node);
     assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST));
@@ -4318,43 +4299,12 @@
     }
     unres->type[unres->count - 1] = type;
 
-    return EXIT_SUCCESS;
-}
-
-/**
- * @brief Try to resolve an unres data item. Logs indirectly.
- *
- * @param[in] unres Unres data structure to use.
- * @param[in] node Data node to use.
- *
- * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
- */
-int
-unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
-{
-    int rc;
-    char *path, *msg;
-
-    assert(unres && node);
-    assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST));
-
-    ly_vlog_hide(1);
-    rc = resolve_unres_data_item(node, type);
-    ly_vlog_hide(0);
-    if (rc != EXIT_FAILURE) {
-        if (rc == -1 && ly_errno == LY_EVALID) {
-            path = strdup(ly_errpath());
-            LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()),
-                   path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
-            free(path);
-            free(msg);
-        }
-        return rc;
+    if (type == UNRES_WHEN) {
+        /* remove previous result */
+        node->when_status = LYD_WHEN;
     }
 
-    print_unres_data_item_fail(node, type);
-
-    return unres_data_addonly(unres, node, type);
+    return EXIT_SUCCESS;
 }
 
 /**
@@ -4369,9 +4319,10 @@
 int
 resolve_unres_data(struct unres_data *unres, struct lyd_node **root)
 {
-    uint32_t i, resolved = 0;
+    uint32_t i, j = 0, resolved = 0, del_items = 0, when_stmt = 0;
     int rc, progress;
     char *msg, *path;
+    struct lyd_node *parent;
 
     assert(unres);
     assert(root && (*root));
@@ -4383,7 +4334,7 @@
     LOGVRB("Resolving unresolved data nodes and their constraints.");
     ly_vlog_hide(1);
 
-    /* when */
+    /* when-stmt first */
     ly_errno = LY_SUCCESS;
     ly_vecode = LYVE_SUCCESS;
     do {
@@ -4392,21 +4343,33 @@
             if (unres->type[i] != UNRES_WHEN) {
                 continue;
             }
+            if (!j) {
+                /* count when-stmt nodes in unres list */
+                when_stmt++;
+            }
+
+            /* resolve when condition only when all parent when conditions are already resolved */
+            for (parent = unres->node[i]->parent;
+                 parent && LYD_WHEN_DONE(parent->when_status);
+                 parent = parent->parent) {
+                if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
+                    /* the parent node was already unlinked, do not resolve this node,
+                     *  it will be removed anyway, so just mark it as resolved
+                     */
+                    unres->node[i]->when_status |= LYD_WHEN_FALSE;
+                    unres->type[i] = UNRES_RESOLVED;
+                    resolved++;
+                    break;
+                }
+            }
+            if (parent) {
+                continue;
+            }
 
             rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
             if (!rc) {
-                if (ly_vecode == LYVE_NOCOND) {
-                    if (root) {
-                        /* auto-delete */
-                        LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
-                               ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
-                        if (*root == unres->node[i]) {
-                            *root = (*root)->next;
-                        }
-                        lyd_free(unres->node[i]);
-                        ly_errno = LY_SUCCESS;
-                        ly_vecode = LYVE_SUCCESS;
-                    } else {
+                if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
+                    if (!root) {
                         /* false when condition */
                         ly_vlog_hide(0);
                         path = strdup(ly_errpath());
@@ -4415,9 +4378,24 @@
                         free(path);
                         free(msg);
                         return -1;
+                    } /* follows else */
+
+                    /* auto-delete */
+                    LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
+                                    ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
+                    if (*root == unres->node[i]) {
+                        *root = (*root)->next;
                     }
+
+                    /* only unlink now, the subtree can contain another nodes stored in the unres list */
+                    lyd_unlink(unres->node[i]);
+                    unres->type[i] = UNRES_DELETE;
+                    del_items++;
+                } else {
+                    unres->type[i] = UNRES_RESOLVED;
                 }
-                unres->type[i] = UNRES_RESOLVED;
+                ly_errno = LY_SUCCESS;
+                ly_vecode = LYVE_SUCCESS;
                 resolved++;
                 progress = 1;
             } else if (rc == -1) {
@@ -4425,8 +4403,47 @@
                 return -1;
             }
         }
+        j = 1;
+    } while (progress && resolved < when_stmt);
 
-    } while (progress);
+    /* do we have some unresolved when-stmt? */
+    if (when_stmt != resolved) {
+        ly_vlog_hide(0);
+        path = strdup(ly_errpath());
+        LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()), path[0] ? " (path: " : "",
+               path[0] ? path : "", path[0] ? ")" : "");
+        free(path);
+        free(msg);
+        return -1;
+    }
+
+    for (i = 0; del_items && i < unres->count; i++) {
+        /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
+        if (unres->type[i] != UNRES_DELETE) {
+            continue;
+        }
+
+        for (j = 0; j < unres->count; j++) {
+            if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
+                continue;
+            }
+
+            /* test if the node is in subtree to be deleted */
+            for (parent = unres->node[j]; parent; parent = parent->parent) {
+                if (parent == unres->node[i]) {
+                    /* yes, it is */
+                    unres->type[j] = UNRES_RESOLVED;
+                    resolved++;
+                    break;
+                }
+            }
+        }
+
+        /* really remove the complete subtree */
+        lyd_free(unres->node[i]);
+        unres->type[i] = UNRES_RESOLVED;
+        del_items--;
+    }
 
     /* rest */
     for (i = 0; i < unres->count; ++i) {