lys_switch_deviation(struct lys_deviation *dev, const struct lys_module *module, struct unres_schema *unres)
{
    int ret, reapply = 0;
    char *parent_path;
    struct lys_node *target = NULL, *parent;
    struct lys_node_inout *inout;
    struct ly_set *set;

    if (!dev->deviate) {
        return;
    }

    if (dev->deviate[0].mod == LY_DEVIATE_NO) {
        if (dev->orig_node) {
            /* removing not-supported deviation ... */
            if (strrchr(dev->target_name, '/') != dev->target_name) {
                /* ... from a parent */

                /* reconnect to its previous position */
                parent = dev->orig_node->parent;
                if (parent && (parent->nodetype == LYS_AUGMENT)) {
                    dev->orig_node->parent = NULL;
                    /* the original node was actually from augment, we have to get know if the augment is
                     * applied (its module is enabled and implemented). If yes, the node will be connected
                     * to the augment and the linkage with the target will be fixed if needed, otherwise
                     * it will be connected only to the augment */
                    if (!(parent->flags & LYS_NOTAPPLIED)) {
                        /* start with removing augment if applied before adding nodes, we have to make sure
                         * that everything will be connect correctly */
                        remove_aug((struct lys_node_augment *)parent);
                        reapply = 1;
                    }
                    /* connect the deviated node back into the augment */
                    lys_node_addchild(parent, NULL, dev->orig_node, 0);
                    if (reapply) {
                        /* augment is supposed to be applied, so fix pointers in target and the status of the original node */
                        assert(lys_node_module(parent)->implemented);
                        parent->flags |= LYS_NOTAPPLIED; /* allow apply_aug() */
                        apply_aug((struct lys_node_augment *)parent, unres);
                    }
                } else if (parent && (parent->nodetype == LYS_USES)) {
                    /* uses child */
                    lys_node_addchild(parent, NULL, dev->orig_node, 0);
                } else {
                    /* non-augment, non-toplevel */
                    parent_path = strndup(dev->target_name, strrchr(dev->target_name, '/') - dev->target_name);
                    ret = resolve_schema_nodeid(parent_path, NULL, module, &set, 0, 1);
                    free(parent_path);
                    if (ret == -1) {
                        LOGINT(module->ctx);
                        ly_set_free(set);
                        return;
                    }
                    target = set->set.s[0];
                    ly_set_free(set);

                    lys_node_addchild(target, NULL, dev->orig_node, 0);
                }
            } else {
                /* ... from top-level data */
                lys_node_addchild(NULL, lys_node_module(dev->orig_node), dev->orig_node, 0);
            }

            dev->orig_node = NULL;
        } else {
            /* adding not-supported deviation */
            ret = resolve_schema_nodeid(dev->target_name, NULL, module, &set, 0, 1);
            if (ret == -1) {
                LOGINT(module->ctx);
                ly_set_free(set);
                return;
            }
            target = set->set.s[0];
            ly_set_free(set);

            /* unlink and store the original node */
            parent = target->parent;
            lys_node_unlink(target);
            if (parent) {
                if (parent->nodetype & (LYS_AUGMENT | LYS_USES)) {
                    /* hack for augment, because when the original will be sometime reconnected back, we actually need
                     * to reconnect it to both - the augment and its target (which is deduced from the deviations target
                     * path), so we need to remember the augment as an addition */
                    /* we also need to remember the parent uses so that we connect it back to it when switching deviation state */
                    target->parent = parent;
                } else if (parent->nodetype & (LYS_RPC | LYS_ACTION)) {
                    /* re-create implicit node */
                    inout = calloc(1, sizeof *inout);
                    LY_CHECK_ERR_RETURN(!inout, LOGMEM(module->ctx), );

                    inout->nodetype = target->nodetype;
                    inout->name = lydict_insert(module->ctx, (inout->nodetype == LYS_INPUT) ? "input" : "output", 0);
                    inout->module = target->module;
                    inout->flags = LYS_IMPLICIT;

                    /* insert it manually */
                    assert(parent->child && !parent->child->next
                    && (parent->child->nodetype == (inout->nodetype == LYS_INPUT ? LYS_OUTPUT : LYS_INPUT)));
                    parent->child->next = (struct lys_node *)inout;
                    inout->prev = parent->child;
                    parent->child->prev = (struct lys_node *)inout;
                    inout->parent = parent;
                }
            }
            dev->orig_node = target;
        }
    } else {
        ret = resolve_schema_nodeid(dev->target_name, NULL, module, &set, 0, 1);
        if (ret == -1) {
            LOGINT(module->ctx);
            ly_set_free(set);
            return;
        }
        target = set->set.s[0];
        ly_set_free(set);

        /* contents are switched */
        lys_node_switch(target, dev->orig_node);
    }
}