package nova;

import java.util.*;

/**
 * Warranty & Liability
 * To the extent permitted by applicable law and unless explicitly
 * otherwise agreed upon, XLOG Technologies AG makes no warranties
 * regarding the provided information. XLOG Technologies AG assumes
 * no liability that any problems might be solved with the information
 * provided by XLOG Technologies AG.
 *
 * Rights & License
 * All industrial property rights regarding the information - copyright
 * and patent rights in particular - are the sole property of XLOG
 * Technologies AG. If the company was not the originator of some
 * excerpts, XLOG Technologies AG has at least obtained the right to
 * reproduce, change and translate the information.
 *
 * Reproduction is restricted to the whole unaltered document. Reproduction
 * of the information is only allowed for non-commercial uses. Selling,
 * giving away or letting of the execution of the library is prohibited.
 * The library can be distributed as part of your applications and libraries
 * for execution provided this comment remains unchanged.
 *
 * Restrictions
 * Only to be distributed with programs that add significant and primary
 * functionality to the library. Not to be distributed with additional
 * software intended to replace any components of the library.
 *
 * Trademarks
 * Jekejeke is a registered trademark of XLOG Technologies AG.
 */
public final class Store {
    public static final int UNDEF_INT = -2;
    public static final Object UNDEF_OBJ = new Object();

    public static final int MASK_PRED_DYNAMIC = 0x00000001;
    public static final int MASK_PRED_SPECIAL = 0x00000002;
    public static final int MASK_PRED_CHECK = 0x00000004;
    public static final int MASK_PRED_ARITHMETIC = 0x00000008;

    public static final int MASK_TOUCH_DYNAMIC = 0x00000001;
    public static final int MASK_TOUCH_BOTTOM = 0x00000002;

    public static final int MASK_REMOVE_REVERSE = 0x00000001;

    public static final int VAR_MASK_SEEN = 0x40000000;

    public static final int VAR_MASK_EVEN = 0x20000000;
    public static final int VAR_MASK_ODD = 0x10000000;
    public static final int VAR_MASK_STATE = VAR_MASK_EVEN | VAR_MASK_ODD;
    public static final int VAR_MASK_SERNO = 0x0FFFFFFF;

    public static HashMap kb = new HashMap();
    public static int stage = -1;

    /**
     * Set the clause and predicate current stage.
     *
     * @param num The current stage.
     */
    public static void set_stage(int num) {
        stage = num;
    }

    /**
     * Set the clause current partition.
     *
     * @param path The current partition.
     */
    public static void set_partition(String path) {
        engine.partition = path;
    }

    /**************************************************************/
    /* Engine                                                     */
    /**************************************************************/

    public static final class Engine {
        public Object signal;
        public Runnable abort;
        public int flags;
        public runtime.Sink text_output;
        public runtime.Sink text_error;
        public runtime.Source text_input;
        public int low;
        public int high;
        public int serno;
        public Variable backtrail;
        public String partition;

        /**
         * Create a slow state engine.
         */
        public Engine() {
            this.signal = UNDEF_OBJ;
            this.abort = () -> {};
            this.flags = 0;
            this.text_output = null;
            this.text_error = null;
            this.text_input = null;
            this.low = 0;
            this.high = 0;
            this.serno = 0;
            this.backtrail = null;
            this.partition = (stage == -1 ? "system" : "user");
        }

    }

    public static Engine engine = new Engine();

    public static void set_engine(Engine ptr) {
        engine = ptr;
    }

    /**************************************************************/
    /* Variable & Compound                                        */
    /**************************************************************/

    public static final class Variable {
        public Object instantiated;
        public int flags;
        public Variable tail;

        /**
         * Create a Prolog variable.
         */
        public Variable() {
            this.instantiated = UNDEF_OBJ;
            this.flags = VAR_MASK_SERNO;
            this.tail = null;
        }

    }

    /**
     * Check whether an object is a variable.
     *
     * @param obj The object.
     * @return boolean True if the object is a variable, otherwise false.
     */
    public static boolean is_variable(Object obj) {
        return obj instanceof Variable;
    }

    public static class Structure {
        public Object functor;
        public Object[] args;

        /**
         * Create a Prolog structure.
         *
         * @param functor The functor.
         * @param args    The arguments.
         */
        public Structure(Object functor, Object[] args) {
            this.functor = functor;
            this.args = args;
        }

    }

    /**
     * Check whether an object is a Prolog structure.
     *
     * @param obj The object.
     * @return True if the object is a compound, otherwise false.
     */
    public static boolean is_structure(Object obj) {
        return obj instanceof Structure;
    }

    public static final class Compound extends Structure {
        public int walk;

        /**
         * Create a Prolog compound.
         *
         * @param functor The functor.
         * @param args    The arguments.
         */
        public Compound(Object functor, Object[] args) {
            super(functor, args);
            this.walk = 0;
        }

    }

    /**
     * Check whether an object is a Prolog compound.
     *
     * @param obj The object.
     * @return True if the object is a compound, otherwise false.
     */
    public static boolean is_compound(Object obj) {
        return obj instanceof Compound;
    }

    public static final class Frozen extends Structure {

        /**
         * Create a Prolog frozen.
         *
         * @param functor The functor.
         * @param args    The arguments.
         */
        public Frozen(Object functor, Object[] args) {
            super(functor, args);
        }

    }

    /**
     * Check whether an object is a Prolog frozen.
     *
     * @param obj The object.
     * @return True if the object is a frozen, otherwise false.
     */
    public static boolean is_frozen(Object obj) {
        return obj instanceof Frozen;
    }

    /**************************************************************/
    /* Place & Skeleton                                           */
    /**************************************************************/

    public static final class Place {
        public final int index;

        /**
         * Create a Albufeira Code place.
         */
        public Place(int index) {
            this.index = index;
        }

    }

    /**
     * Check whether an object is a place.
     *
     * @param obj The object.
     * @return boolean True if the object is a place, otherwise false.
     */
    public static boolean is_place(Object obj) {
        return obj instanceof Place;
    }

    public static final class Skeleton {
        public final Object functor;
        public final Object[] args;

        /**
         * Create a Albufeira Code skeleton.
         *
         * @param functor The functor.
         * @param args    The arguments.
         */
        public Skeleton(Object functor, Object[] args) {
            this.functor = functor;
            this.args = args;
        }

    }

    /**
     * Check whether an object is a skeleton.
     *
     * @param obj The object.
     * @return boolean True if the object is a skeleton, otherwise false.
     */
    public static boolean is_skeleton(Object obj) {
        return obj instanceof Skeleton;
    }

    /**************************************************************/
    /* Quote                                                      */
    /**************************************************************/

    public static final class Quote {
        public final Object obj;

        /**
         * Create an Albufeira code quote.
         *
         * @param obj The Albufeira code.
         */
        public Quote(Object obj) {
            this.obj = obj;
        }

    }

    /**
     * Check whether an object is a quote.
     *
     * @param obj The object.
     * @return boolean True if the object is a quote, otherwise false.
     */
    public static boolean is_quote(Object obj) {
        return obj instanceof Quote;
    }

    public static void unquote_objects(Object[] body) {
        for (int i = 0; i < body.length; i++) {
            Object alpha = body[i];
            if (is_quote(alpha))
                body[i] = ((Quote) alpha).obj;
        }
    }

    /**************************************************************/
    /* Iterative Stack                                            */
    /**************************************************************/

    public static final class Item {
        public final Structure first;
        public Object second;
        public int idx;

        /**
         * Create a work item.
         *
         * @param first  The first Prolog term.
         * @param second The second Prolog term.
         * @param idx The index.
         */
        public Item(Structure first, Object second, int idx) {
            this.first = first;
            this.second = second;
            this.idx = idx;
        }

    }

    public static List stack_push(List stack, Object elem) {
        if (stack == null)
            stack = new ArrayList();
        stack.add(elem);
        return stack;
    }

    public static Object stack_peek(List stack) {
        if (stack == null)
            return null;
        if (stack.size() == 0)
            return null;
        return stack.get(stack.size()-1);
    }

    public static void stack_pop(List stack) {
        stack.remove(stack.size()-1);
    }

    /**************************************************************/
    /* Association Map                                            */
    /**************************************************************/

    public static Object assoc_get(Map map, Object key) {
        if (map == null)
            return null;
        return map.get(key);
    }

    public static Map assoc_set(Map map, Object key, Object value) {
        if (map == null)
            map = new HashMap();
        map.put(key, value);
        return map;
    }

    /**************************************************************/
    /* Clauses Lifecycle                                          */
    /**************************************************************/

    public static final class Goal {
        public final int size;
        public final Object[] body;
        public final int cutvar;

        public Goal(int size, Object[] body, int cutvar) {
            this.size = size;
            this.body = body;
            this.cutvar = cutvar;
        }

    }

    /**
     * Check whether the object is a goal.
     *
     * @param obj The object.
     * @return boolean if the object is a goal, otherwise false.
     */
    public static boolean is_goal(Object obj) {
        return obj instanceof Goal;
    }

    public static final class Clause {
        public final int size;
        public final Object[] head;
        public final Object[] body;
        public final int cutvar;
        public final Object idxval;
        public int creator;
        public int remover;
        public String shard;

        public Clause(int size, Object[] head, Object[] body, int cutvar, Object idxval) {
            this.size = size;
            this.head = head;
            this.body = body;
            this.cutvar = cutvar;
            this.idxval = idxval;
            this.creator = stage;
            this.remover = UNDEF_INT;
            this.shard = "";
        }

    }

    /**
     * Check whether the object is a clause.
     *
     * @param obj The object.
     * @return boolean if the object is a clause, otherwise false.
     */
    public static boolean is_clause(Object obj) {
        return obj instanceof Clause;
    }

    public static final class Logical {
        public Clause[] cache;
        public int count;
        public Handler.Rope data;

        /**
         * Create a logical.
         *
         * @param cache The cache of non-deleted clauses.
         * @param count The counter of non-deleted clauses.
         * @param data  The clause list.
         */
        public Logical(Clause[] cache, int count, Handler.Rope data) {
            this.cache = cache;
            this.count = count;
            this.data = data;
        }

    }

    /**
     * Check whether an object is a logical.
     *
     * @param obj The object.
     * @return boolean if the object is a logical, otherwise false.
     */
    public static boolean is_logical(Object obj) {
        return obj instanceof Logical;
    }

    /**************************************************************/
    /* Knowledgebase                                              */
    /**************************************************************/

    public static final class Provable {
        public int flags;
        public Logical rope;
        public Logical nonguard;
        public HashMap idxmap;
        public Object func;
        public int creator;
        public int remover;
        public Provable overlay;

        /**
         * Create a provable.
         *
         * @param flags The flags.
         */
        public Provable(int flags) {
            this.flags = flags;
            this.rope = null;
            this.nonguard = null;
            this.idxmap = null;
            this.func = null;
            this.creator = stage;
            this.remover = UNDEF_INT;
            this.overlay = null;
        }

    }

    /**
     * Check whether an object is a provable.
     *
     * @param obj The object.
     * @return boolean True if the object is a provable, otherwise false.
     */
    public static boolean is_provable(Object obj) {
        return obj instanceof Provable;
    }

    public static final class Cache {
        public Provable link;
        public String name;

        /**
         * Create a cache node.
         *
         * @param name The functor.
         */
        public Cache(String name) {
            this.link = null;
            this.name = name;
        }
    }

    /**
     * Check whether an object is a cache.
     *
     * @param obj The object.
     * @return boolean True if the object is a cache, otherwise false.
     */
    public static boolean is_cache(Object obj) {
        return obj instanceof Cache;
    }

    /******************************************************************/
    /* Snapshot Data                                                  */
    /******************************************************************/

    /**
     * Make snapshot of a logical.
     *
     * @param rope The logical.
     * @return array The clause list snapshot.
     */
    public static Clause[] snapshot_data(Logical rope) {
        Clause[] res = rope.cache;
        if (res == null) {
            res = new Clause[rope.count];
            rope_copy(res, rope);
            rope.cache = res;
        }
        return res;
    }

    static void rope_copy(Clause[] res, Logical rope) {
        Handler.Rope data = rope.data;
        int j = 0;
        for (int i = 0; i < data.size(); i++) {
            Clause clause = (Clause)data.get(i);
            if (clause.remover == UNDEF_INT)
                res[j++] = clause;
        }
    }

    /******************************************************************/
    /* Linked Provables                                               */
    /******************************************************************/

    /**
     * Retrieve a provable from monomorphic cache.
     *
     * @param cache The cache.
     * @param arity The arity.
     * @return The provable or null.
     */
    public static Provable ensure_link(Cache cache, int arity) {
        Provable peek = cache.link;
        if (peek == null || peek.remover != UNDEF_INT) {
            peek = pred_link(cache.name, arity);
            cache.link = peek;
        }
        return peek;
    }

    /**
     * Retrieve a provable by predicate indicator.
     *
     * @param functor The functor.
     * @param arity   The arity.
     * @return The provable or null.
     */
    public static Provable pred_link(String functor, int arity) {
        if (arity < 0)
            return null;
        Handler.Rope temp = (Handler.Rope)kb.get(functor);
        if (temp == null)
            return null;
        Provable peek = (arity < temp.size() ? (Provable)temp.get(arity) : null);
        if (peek == null || peek.remover != UNDEF_INT)
            return null;
        return peek;
    }

    /**
     * The function returns an anonymous predicate for the given clauses.
     *
     * @param rope The clauses.
     * @return Provable predicate.
     */
    public static Provable make_defined(Object[] rope) {
        Provable peek = new Provable(0);
        peek.rope = new_rope();
        peek.nonguard = new_rope();
        peek.idxmap = new HashMap();
        for (int i = 0; i < rope.length; i++)
            add_peek(peek, (Clause) rope[i], MASK_TOUCH_BOTTOM);
        return peek;
    }

    static Logical new_rope() {
        return new Logical(null, 0, new Handler.Rope());
    }

    /**************************************************************/
    /* Dynamic Predicates                                         */
    /**************************************************************/

    /**
     * Create a new dynamic predicate entry.
     *
     * @param functor The functor.
     * @param arity   The arity.
     * @param flags   The flags.
     */
    public static void pred_touch(String functor, int arity, int flags) {
        Handler.Rope temp = (Handler.Rope)kb.get(functor);
        if (temp == null) {
            temp = new Handler.Rope();
            kb.put(functor, temp);
        }
        Provable peek = (arity < temp.size() ? (Provable)temp.get(arity) : null);
        if (peek == null || peek.remover != UNDEF_INT) {
            Provable res = make_defined(Machine.VOID_ARGS);
            if (peek != null)
                res.overlay = peek;
            if ((flags & MASK_TOUCH_DYNAMIC) != 0)
                res.flags |= MASK_PRED_DYNAMIC;
            while (arity >= temp.size())
                temp.add(null);
            temp.set(arity, res);
        } else {
            if (!is_logical(peek.rope))
                throw Machine.make_error(new Compound("permission_error",
                        new Object[]{"modify", "static_procedure",
                                Machine.make_indicator(functor, arity)}));
            if ((flags & MASK_TOUCH_DYNAMIC) != 0)
                if ((peek.flags & MASK_PRED_DYNAMIC) == 0)
                    throw Machine.make_error(new Compound("permission_error",
                            new Object[]{"modify", "static_procedure",
                                    Machine.make_indicator(functor, arity)}));
        }
    }

    /*********************************************************************/
    /* Destroy Provable                                                 */
    /*********************************************************************/

    /**
     * Remove a predicate from the knowledge base.
     *
     * @param functor The functor.
     * @param arity   The arity.
     */
    public static void pred_destroy(String functor, int arity) {
        Handler.Rope temp = (Handler.Rope)kb.get(functor);
        if (temp == null)
            return;
        Provable peek = (arity < temp.size() ? (Provable)temp.get(arity) : null);
        if (peek == null || peek.remover != UNDEF_INT)
            return;
        if (peek.creator == stage) {
            peek = clear_pop(peek);
            temp.set(arity, peek);
            if (peek == null && trim_arities(temp))
                kb.remove(functor);
        } else {
            peek.remover = stage;
        }
    }

    /**
     * Clear and pop a provable.
     *
     * @param peek The provable.
     * @return The parent provable.
     */
    private static Provable clear_pop(Provable peek) {
        peek.remover = stage;
        peek.rope = null;
        peek.idxmap = null;
        peek.nonguard = null;
        peek.func = null;

        Provable back = peek;
        peek = back.overlay;
        back.overlay = null;
        return peek;
    }

    /**
     * Trim the arities array.
     *
     * @param peek The arities array.
     * @return boolean True if empty, otherwise fale.
     */
    private static boolean trim_arities(Handler.Rope peek) {
        int pos = peek.size();
        while (pos > 0 && peek.get(pos - 1) == null)
            pos--;
        if (pos == 0)
            return true;
        if (pos != peek.size())
            peek.removeRange(pos, peek.size());
        return false;
    }

    /**************************************************************/
    /* Clauses Transactions                                       */
    /**************************************************************/

    /**
     * Rollback the clauses.
     */
    public static void clear() {
        Iterator it = kb.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            Handler.Rope temp = (Handler.Rope)entry.getValue();
            for (int i = 0; i < temp.size(); i++) {
                Provable peek = (Provable)temp.get(i);
                if (peek == null)
                    continue;
                if (peek.creator == stage) {
                    peek = clear_pop(peek);
                    temp.set(i, peek);
                    if (peek == null)
                        continue;
                }
                if (peek.remover == stage)
                    peek.remover = UNDEF_INT;
                if (is_logical(peek.rope))
                    rollback_peek(peek);
            }
            if (trim_arities(temp))
                it.remove();
        }
    }

    /**
     * Rollback the clauses of a predicate.
     *
     * @param peek The predicate.
     */
    static void rollback_peek(Provable peek) {
        if (!has_action(peek.rope))
            return;
        Iterator it = peek.idxmap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            if (has_action((Logical)entry.getValue())) {
                rollback_rope((Logical)entry.getValue(), false);
                if (((Logical)entry.getValue()).data.size() == 0)
                    it.remove();
            }
        }
        if (has_action(peek.nonguard))
            rollback_rope(peek.nonguard, false);
        rollback_rope(peek.rope, true);
    }

    /**
     * Check whether a logical has some action.
     *
     * @param rope The logical.
     * @return boolean if the logical has some action, false otherwise.
     */
    static boolean has_action(Logical rope) {
        Handler.Rope data = rope.data;
        for (int i = 0; i < data.size(); i++) {
            Clause clause = (Clause)data.get(i);
            if (clause.creator == stage)
                return true;
            if (clause.remover == stage)
                return true;
        }
        return false;
    }

    /**
     * Rollback clauses from a logical.
     *
     * @param rope   The logical.
     * @param update The update flag.
     */
    static void rollback_rope(Logical rope, boolean update) {
        Handler.Rope data = rope.data;
        int j = 0;
        for (int i = 0; i < data.size(); i++) {
            Clause clause = (Clause)data.get(i);
            if (clause.creator == stage) {
                rope.count--;
            } else {
                if (clause.remover == stage) {
                    if (update)
                        clause.remover = UNDEF_INT;
                    rope.count++;
                }
                data.set(j++, clause);
            }
        }
        data.removeRange(j, data.size());
        rope.cache = null;
    }

    /*********************************************************************/
    /* Clause Addition                                                   */
    /*********************************************************************/

    /**
     * Enhance the knowledge base by a claus or predicate.
     *
     * @param functor        The functor.
     * @param arity          The arity.
     * @param clause_or_pred The clause or predicate.
     */
    public static void add(String functor, int arity,
                           Object clause_or_pred) {
        add_clause(functor, arity, clause_or_pred, MASK_TOUCH_BOTTOM);
    }

    /**
     * Enhance the knowledge base by a claus or predicate.
     *
     * @param functor        The functor.
     * @param arity          The arity.
     * @param clause_or_pred The clause or predicate.
     * @param flags          The flags.
     */
    public static void add_clause(String functor, int arity,
                                  Object clause_or_pred, int flags) {
        Handler.Rope temp = (Handler.Rope)kb.get(functor);
        if (temp == null) {
            temp = new Handler.Rope();
            kb.put(functor, temp);
        }
        Provable peek = (arity < temp.size() ? (Provable)temp.get(arity) : null);
        if (is_clause(clause_or_pred)) {
            if (peek == null || peek.remover != UNDEF_INT) {
                Provable res = make_defined(Machine.VOID_ARGS);
                if (peek != null)
                    res.overlay = peek;
                if ((flags & MASK_TOUCH_DYNAMIC) != 0)
                    res.flags |= MASK_PRED_DYNAMIC;
                while (arity >= temp.size())
                    temp.add(null);
                temp.set(arity, res);
                peek = res;
            } else {
                if (!is_logical(peek.rope))
                    throw Machine.make_error(new Compound("permission_error",
                            new Object[]{"modify", "static_procedure",
                                    Machine.make_indicator(functor, arity)}));
                if ((flags & MASK_TOUCH_DYNAMIC) != 0)
                    if ((peek.flags & MASK_PRED_DYNAMIC) == 0)
                        throw Machine.make_error(new Compound("permission_error",
                                new Object[]{"modify", "static_procedure",
                                        Machine.make_indicator(functor, arity)}));
            }
            if ((flags & MASK_TOUCH_DYNAMIC) == 0)
                ((Clause) clause_or_pred).shard = engine.partition;
            add_peek(peek, (Clause) clause_or_pred, flags);
        } else if (!is_goal(clause_or_pred)) {
            if (peek == null || peek.remover != UNDEF_INT) {
                Provable res = (Provable) clause_or_pred;
                if (peek != null)
                    res.overlay = peek;
                while (arity >= temp.size())
                    temp.add(null);
                temp.set(arity, res);
            } else {
                throw Machine.make_error(new Compound("permission_error",
                        new Object[]{"coerce", "procedure",
                                Machine.make_indicator(functor, arity)}));
            }
        } else {
            throw Machine.make_error(new Compound("permission_error",
                    new Object[]{"coerce", "procedure",
                            Machine.make_indicator(functor, arity)}));
        }
    }

    public static void add_peek(Provable peek, Clause clause, int flags) {
        add_rope(peek.rope, clause, flags);
        Object idxval = clause.idxval;
        if (idxval == UNDEF_OBJ) {
            Iterator it = peek.idxmap.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry entry = (Map.Entry)it.next();
                add_rope((Logical)entry.getValue(), clause, flags);
            }
            add_rope(peek.nonguard, clause, flags);
        } else {
            Logical value = (Logical)peek.idxmap.get(idxval);
            if (value == null) {
                value = clone_rope(peek.nonguard);
                peek.idxmap.put(idxval, value);
            }
            add_rope(value, clause, flags);
        }
    }

    static void add_rope(Logical rope, Clause clause, int flags) {
        if ((flags & MASK_TOUCH_BOTTOM) != 0) {
            rope.data.add(clause);
        } else {
            rope.data.add(0, clause);
        }
        rope.count++;
        rope.cache = null;
    }

    static Logical clone_rope(Logical rope) {
        return new Logical(rope.cache, rope.count,
                (Handler.Rope) rope.data.clone());
    }

    /******************************************************************/
    /* Clause Removal                                                 */
    /******************************************************************/

    /**
     * Remove a clause from the knowledge base.
     *
     * @param functor The functor.
     * @param arity   The arity.
     * @param clause  The clause.
     * @param flags   The flags.
     * @return boolean True if the clause was removed, false otherwise.
     */
    public static boolean remove_clause(String functor, int arity,
                                        Object clause, int flags) {
        Handler.Rope temp = (Handler.Rope)kb.get(functor);
        if (temp == null)
            return false;
        Provable peek = (arity < temp.size() ? (Provable)temp.get(arity) : null);
        if (peek == null || peek.remover != UNDEF_INT)
            return false;
        if (!is_logical(peek.rope))
            throw Machine.make_error(new Compound("permission_error",
                    new Object[]{"modify", "static_procedure",
                            Machine.make_indicator(functor, arity)}));
        return remove_peek(peek, (Clause) clause, flags);
    }

    static boolean remove_peek(Provable peek, Clause clause, int flags) {
        if (clause.remover != UNDEF_INT)
            return false;
        if (!remove_rope(peek.rope, clause, flags))
            return false;
        Object idxval = clause.idxval;
        if (idxval == UNDEF_OBJ) {
            Iterator it = peek.idxmap.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry entry = (Map.Entry)it.next();
                remove_rope((Logical)entry.getValue(), clause, flags);
                if (((Logical)entry.getValue()).data.size() == 0)
                    it.remove();
            }
            remove_rope(peek.nonguard, clause, flags);
        } else {
            Logical value = (Logical)peek.idxmap.get(idxval);
            remove_rope(value, clause, flags);
            if (value.data.size() == 0)
                peek.idxmap.remove(idxval);
        }
        clause.remover = stage;
        return true;
    }

    static boolean remove_rope(Logical rope, Clause clause, int flags) {
        Handler.Rope data = rope.data;
        int index;
        if ((flags & MASK_REMOVE_REVERSE) == 0) {
            index = data.indexOf(clause);
        } else {
            index = data.lastIndexOf(clause);
        }
        if (index == -1)
            return false;
        if (clause.creator == stage)
            data.remove(index);
        rope.count--;
        rope.cache = null;
        return true;
    }

}
