public class CL {
    protected final static boolean fDebugOn = false;
    public static boolean fTraceOn = false; // true;
    protected final static boolean fTraceAdded = false;
    protected final static boolean fGC = false;

    protected static void debugprint(String s) {
        System.err.println(s);
    }

    protected static void traceprint(String s) {
        System.err.println(s);
    }

    protected static void fnenterprint(String s) {
        System.err.println("* " + s);
    }

    protected static void fnexitprint(String s) {
        System.err.println("- " + s);
    }

    public static final byte GEQ = 1;
    public static final byte LEQ = 2;

    public static ClLinearExpression Plus(ClLinearExpression e1, ClLinearExpression e2) {
        return e1.plus(e2);
    }

    public static ClLinearExpression Plus(ClLinearExpression e1, double e2) {
        return e1.plus(new ClLinearExpression(e2));
    }

    public static ClLinearExpression Plus(double e1, ClLinearExpression e2) {
        return (new ClLinearExpression(e1)).plus(e2);
    }

    public static ClLinearExpression Plus(ClVariable e1, ClLinearExpression e2) {
        return (new ClLinearExpression(e1)).plus(e2);
    }

    public static ClLinearExpression Plus(ClLinearExpression e1, ClVariable e2) {
        return e1.plus(new ClLinearExpression(e2));
    }

    public static ClLinearExpression Plus(ClVariable e1, double e2) {
        return (new ClLinearExpression(e1)).plus(new ClLinearExpression(e2));
    }

    public static ClLinearExpression Plus(double e1, ClVariable e2) {
        return (new ClLinearExpression(e1)).plus(new ClLinearExpression(e2));
    }

    public static ClLinearExpression Minus(ClLinearExpression e1, ClLinearExpression e2) {
        return e1.minus(e2);
    }

    public static ClLinearExpression Minus(double e1, ClLinearExpression e2) {
        return (new ClLinearExpression(e1)).minus(e2);
    }

    public static ClLinearExpression Minus(ClLinearExpression e1, double e2) {
        return e1.minus(new ClLinearExpression(e2));
    }

    public static ClLinearExpression Times(ClLinearExpression e1, ClLinearExpression e2) throws NonlinearExpressionException {
        return e1.times(e2);
    }

    public static ClLinearExpression Times(ClLinearExpression e1, ClVariable e2) throws NonlinearExpressionException {
        return e1.times(new ClLinearExpression(e2));
    }

    public static ClLinearExpression Times(ClVariable e1, ClLinearExpression e2) throws NonlinearExpressionException {
        return (new ClLinearExpression(e1)).times(e2);
    }

    public static ClLinearExpression Times(ClLinearExpression e1, double e2) throws NonlinearExpressionException {
        return e1.times(new ClLinearExpression(e2));
    }

    public static ClLinearExpression Times(double e1, ClLinearExpression e2) throws NonlinearExpressionException {
        return (new ClLinearExpression(e1)).times(e2);
    }

    public static ClLinearExpression Times(double n, ClVariable clv) throws NonlinearExpressionException {
        return (new ClLinearExpression(clv, n));
    }

    public static ClLinearExpression Times(ClVariable clv, double n) throws NonlinearExpressionException {
        return (new ClLinearExpression(clv, n));
    }

    public static ClLinearExpression Divide(ClLinearExpression e1, ClLinearExpression e2) throws NonlinearExpressionException {
        return e1.divide(e2);
    }

    public static boolean approx(double a, double b) {
        double epsilon = 1.0e-8;
        if (a == 0.0) {
            return (Math.abs(b) < epsilon);
        } else if (b == 0.0) {
            return (Math.abs(a) < epsilon);
        } else {
            return (Math.abs(a - b) < Math.abs(a) * epsilon);
        }
    }

    public static boolean approx(ClVariable clv, double b) {
        return approx(clv.getValue(), b);
    }

    static boolean approx(double a, ClVariable clv) {
        return approx(a, clv.getValue());
    }
} public class CLInternalError extends CLException {

    public CLInternalError(String s) {
        super(s);
    }

} public class ClSimplexSolver extends ClTableau {

    // the arrays of positive and negative error vars for the stay constraints
    // (need both positive and negative since they have only non-negative values)
    private List<ClAbstractVariable> _stayMinusErrorVars;
    private List<ClAbstractVariable> _stayPlusErrorVars;

    // give error variables for a non required constraint,
    // maps to ClSlackVariable-s
    private IdentityHashMap<ClConstraint, Set<ClAbstractVariable>> _errorVars;

    // Return a lookup table giving the marker variable for each
    // constraint (used when deleting a constraint).
    private IdentityHashMap<ClConstraint, ClAbstractVariable> _markerVars;

    private ClObjectiveVariable _objective;

    // Map edit variables to ClEditInfo-s.
    // ClEditInfo instances contain all the information for an
    // edit constraint (the edit plus/minus vars, the index [for old-style
    // resolve(List...) interface], and the previous value.
    // (ClEditInfo replaces the parallel vectors from the Smalltalk impl.)
    private IdentityHashMap<ClVariable, ClEditInfo> _editVarMap;

    private long _slackCounter;
    private long _artificialCounter;
    private long _dummyCounter;

    private List<ClDouble> _resolve_pair;

    private double _epsilon;

    private boolean _fOptimizeAutomatically;
    private boolean _fNeedsSolving;

    private LinkedList<Integer> _stkCedcns;

    // Ctr initializes the fields, and creates the objective row
    public ClSimplexSolver() {
        _stayMinusErrorVars = new ArrayList<ClAbstractVariable>();
        _stayPlusErrorVars = new ArrayList<ClAbstractVariable>();
        _errorVars = new IdentityHashMap<ClConstraint, Set<ClAbstractVariable>>();
        _markerVars = new IdentityHashMap<ClConstraint, ClAbstractVariable>();

        _resolve_pair = new ArrayList<ClDouble>(2);
        _resolve_pair.add(new ClDouble(0));
        _resolve_pair.add(new ClDouble(0));

        _objective = new ClObjectiveVariable("Z");

        _editVarMap = new IdentityHashMap<ClVariable, ClEditInfo>();

        _slackCounter = 0;
        _artificialCounter = 0;
        _dummyCounter = 0;
        _epsilon = 1e-8;

        _fOptimizeAutomatically = true;
        _fNeedsSolving = false;

        ClLinearExpression e = new ClLinearExpression();
        _rows.put(_objective, e);
        _stkCedcns = new LinkedList<Integer>();
        _stkCedcns.push(new Integer(0));

        if (fTraceOn)
            traceprint("objective expr == " + rowExpression(_objective));
    }

    // Convenience function for creating a linear inequality constraint
    public final ClSimplexSolver addLowerBound(ClAbstractVariable v, double lower) throws RequiredConstraintFailureException,
            CLInternalError {
        ClLinearInequality cn = new ClLinearInequality(v, CL.GEQ, new ClLinearExpression(lower));
        return addConstraint(cn);
    }

    // Convenience function for creating a linear inequality constraint
    public final ClSimplexSolver addUpperBound(ClAbstractVariable v, double upper) throws RequiredConstraintFailureException,
            CLInternalError {
        ClLinearInequality cn = new ClLinearInequality(v, CL.LEQ, new ClLinearExpression(upper));
        return addConstraint(cn);
    }

    // Convenience function for creating a pair of linear inequality constraint
    public final ClSimplexSolver addBounds(ClAbstractVariable v, double lower, double upper)
            throws RequiredConstraintFailureException, CLInternalError {
        addLowerBound(v, lower);
        addUpperBound(v, upper);
        return this;
    }

    // Add constraint "cn" to the solver
    public final ClSimplexSolver addConstraint(ClConstraint cn) throws RequiredConstraintFailureException, CLInternalError {
        if (fTraceOn)
            fnenterprint("addConstraint: " + cn);

        List<ClSlackVariable> eplus_eminus = new ArrayList<ClSlackVariable>(2);
        ClDouble prevEConstant = new ClDouble();
        ClLinearExpression expr = newExpression(cn, eplus_eminus, prevEConstant);
        boolean fAddedOkDirectly = false;

        try {
            fAddedOkDirectly = tryAddingDirectly(expr);
            if (!fAddedOkDirectly) {
                // could not add directly
                addWithArtificialVariable(expr);
            }
        } catch (RequiredConstraintFailureException err) {
            // /try {
            // / removeConstraint(cn); // FIXGJB
            // } catch (ExCLConstraintNotFound errNF) {
            // This should not possibly happen
            // / System.err.println("ERROR: could not find a constraint just added\n");
            // /}
            throw err;
        }

        _fNeedsSolving = true;

        if (cn.isEditConstraint()) {
            int i = _editVarMap.size();
            ClEditConstraint cnEdit = (ClEditConstraint) cn;
            ClSlackVariable clvEplus = eplus_eminus.get(0);
            ClSlackVariable clvEminus = eplus_eminus.get(1);
            _editVarMap.put(cnEdit.variable(), new ClEditInfo(cnEdit, clvEplus, clvEminus, prevEConstant.doubleValue(), i));
        }

        if (_fOptimizeAutomatically) {
            optimize(_objective);
            setExternalVariables();
        }

        cn.addedTo(this);
        return this;
    }

    // Same as addConstraint, except returns false if the constraint
    // resulted in an unsolvable system (instead of throwing an exception)
    public final boolean addConstraintNoException(ClConstraint cn) throws CLInternalError {
        if (fTraceOn)
            fnenterprint("addConstraintNoException: " + cn);

        try {
            addConstraint(cn);
            return true;
        } catch (RequiredConstraintFailureException e) {
            return false;
        }
    }

    // Add an edit constraint for "v" with given strength
    public final ClSimplexSolver addEditVar(ClVariable v, ClStrength strength) throws CLInternalError {
        try {
            ClEditConstraint cnEdit = new ClEditConstraint(v, strength);
            return addConstraint(cnEdit);
        } catch (RequiredConstraintFailureException e) {
            // should not get this
            throw new CLInternalError("Required failure when adding an edit variable");
        }
    }

    // default to strength = strong
    public final ClSimplexSolver addEditVar(ClVariable v) throws CLInternalError {
        return addEditVar(v, ClStrength.strong);
    }

    public void removeEditVar(ClVariable v) {
        ClEditInfo cei = _editVarMap.get(v);
        removeEditVar(v, cei);
    }

    // Remove the edit constraint previously added for variable v
    private void removeEditVar(ClVariable v, ClEditInfo cei) {
        ClConstraint cn = cei.Constraint();
        removeConstraintInternal(cn, v);
        cn.removedFrom(this);
    }

    // beginEdit() should be called before sending
    // resolve() messages, after adding the appropriate edit variables
    public final ClSimplexSolver beginEdit() throws CLInternalError {
        assert _editVarMap.size() > 0 : "_editVarMap.size() > 0";
        // may later want to do more in here
        _infeasibleRows.clear();
        resetStayConstants();
        _stkCedcns.addFirst(new Integer(_editVarMap.size()));
        return this;
    }

    // endEdit should be called after editing has finished
    // for now, it just removes all edit variables
    public final ClSimplexSolver endEdit() throws CLInternalError {
        assert _editVarMap.size() > 0 : "_editVarMap.size() > 0";
        resolve();
        _stkCedcns.pop();
        int n = _stkCedcns.peek().intValue();
        removeEditVarsTo(n);
        // may later want to do more in here
        return this;
    }

    // removeAllEditVars() just eliminates all the edit constraints
    // that were added
    public final ClSimplexSolver removeAllEditVars() throws CLInternalError {
        return removeEditVarsTo(0);
    }

    // remove the last added edit vars to leave only n edit vars left
    public final ClSimplexSolver removeEditVarsTo(int n) throws CLInternalError {
        try {
            // for (Enumeration e = _editVarMap.keys(); e.hasMoreElements();) {
            // ClVariable v = (ClVariable) e.nextElement();
            // ClEditInfo cei = (ClEditInfo) _editVarMap.get(v);
            for (Iterator<Map.Entry<ClVariable, ClEditInfo>> i = _editVarMap.entrySet().iterator(); i.hasNext();) {
                Map.Entry<ClVariable, ClEditInfo> entry = i.next();
                if (entry.getValue().Index() >= n) {
                    removeEditVar(entry.getKey(), entry.getValue());
                    i.remove();
                }
            }
            assert _editVarMap.size() == n : "_editVarMap.size() == n";

            return this;
        } catch (ConstraintNotFoundException e) {
            // should not get this
            throw new CLInternalError("Constraint not found in removeEditVarsTo");
        }
    }

    // Add weak stays to the x and y parts of each point. These have
    // increasing weights so that the solver will try to satisfy the x
    // and y stays on the same point, rather than the x stay on one and
    // the y stay on another.
    public final ClSimplexSolver addPointStays(List<ClPoint> listOfPoints) throws RequiredConstraintFailureException,
            CLInternalError {
        if (fTraceOn)
            fnenterprint("addPointStays" + listOfPoints);
        double weight = 1.0;
        final double multiplier = 2.0;
        int size = listOfPoints.size();
        for (int i = 0; i < size; i++) {
            addPointStay(listOfPoints.get(i), weight);
            weight *= multiplier;
        }
        return this;
    }

    public final ClSimplexSolver addPointStay(ClVariable vx, ClVariable vy, double weight)
            throws RequiredConstraintFailureException, CLInternalError {
        addStay(vx, ClStrength.weak, weight);
        addStay(vy, ClStrength.weak, weight);
        return this;
    }

    public final ClSimplexSolver addPointStay(ClVariable vx, ClVariable vy) throws RequiredConstraintFailureException,
            CLInternalError {
        addPointStay(vx, vy, 1.0);
        return this;
    }

    public final ClSimplexSolver addPointStay(ClPoint clp, double weight) throws RequiredConstraintFailureException,
            CLInternalError {
        addStay(clp.getX(), ClStrength.weak, weight);
        addStay(clp.getY(), ClStrength.weak, weight);
        return this;
    }

    public final ClSimplexSolver addPointStay(ClPoint clp) throws RequiredConstraintFailureException, CLInternalError {
        addPointStay(clp, 1.0);
        return this;
    }

    // Add a stay of the given strength (default to weak) of v to the tableau
    public final ClSimplexSolver addStay(ClVariable v, ClStrength strength, double weight)
            throws RequiredConstraintFailureException, CLInternalError {
        ClStayConstraint cn = new ClStayConstraint(v, strength, weight);
        return addConstraint(cn);
    }

    // default to weight == 1.0
    public final ClSimplexSolver addStay(ClVariable v, ClStrength strength) throws RequiredConstraintFailureException,
            CLInternalError {
        addStay(v, strength, 1.0);
        return this;
    }

    // default to strength = weak
    public final ClSimplexSolver addStay(ClVariable v) throws RequiredConstraintFailureException, CLInternalError {
        addStay(v, ClStrength.weak, 1.0);
        return this;
    }

    public ClSimplexSolver removeConstraint(ClConstraint cn) throws ConstraintNotFoundException, CLInternalError {
        removeConstraintInternal(cn, null);
        cn.removedFrom(this);
        return this;
    }

    // Remove the constraint cn from the tableau
    // Also remove any error variable associated with cn
    private final ClSimplexSolver removeConstraintInternal(ClConstraint cn, ClAbstractVariable dontRemove)
            throws ConstraintNotFoundException, CLInternalError {
        if (fTraceOn)
            fnenterprint("removeConstraint: " + cn);
        if (fTraceOn)
            traceprint(this.toString());

        _fNeedsSolving = true;

        resetStayConstants();

        ClLinearExpression zRow = rowExpression(_objective);

        Set<ClAbstractVariable> eVars = _errorVars.get(cn);
        if (fTraceOn)
            traceprint("eVars == " + eVars);

        if (eVars != null) {
            for (ClAbstractVariable clv : eVars) {
                final ClLinearExpression expr = rowExpression(clv);
                if (expr == null) {
                    zRow.addVariable(clv, -cn.weight() * cn.strength().getSymbolicWeight().asDouble(), _objective, this);
                } else { // the error variable was in the basis
                    zRow.addExpression(expr, -cn.weight() * cn.strength().getSymbolicWeight().asDouble(), _objective, this);
                }
            }
        }

        ClAbstractVariable marker = _markerVars.remove(cn);
        if (marker == null) {
            throw new ConstraintNotFoundException();
        }

        if (fTraceOn)
            traceprint("Looking to remove var " + marker);

        if (rowExpression(marker) == null) {
            // not in the basis, so need to do some work
            Set<ClAbstractVariable> col = _columns.get(marker);

            if (fTraceOn)
                traceprint("Must pivot -- columns are " + col);

            ClAbstractVariable exitVar = null;
            double minRatio = 0.0;
            for (ClAbstractVariable v : col) {
                if (v.isRestricted()) {
                    final ClLinearExpression expr = rowExpression(v);
                    double coeff = expr.coefficientFor(marker);
                    if (fTraceOn)
                        traceprint("Marker " + marker + "'s coefficient in " + expr + " is " + coeff);
                    if (coeff < 0.0) {
                        double r = -expr.constant() / coeff;
                        // Bland's anti-cycling rule:
                        // if multiple variables are about the same,
                        // always pick the lowest via some total
                        // ordering -- I use their hash codes
                        if (exitVar == null || r < minRatio || (CL.approx(r, minRatio) && v.hashCode() < exitVar.hashCode())) {
                            minRatio = r;
                            exitVar = v;
                        }
                    }
                }
            }
            if (exitVar == null) {
                if (fTraceOn)
                    traceprint("exitVar is still null");
                for (ClAbstractVariable v : col) {
                    if (v.isRestricted()) {
                        final ClLinearExpression expr = rowExpression(v);
                        double coeff = expr.coefficientFor(marker);
                        double r = expr.constant() / coeff;
                        if (exitVar == null || r < minRatio) {
                            minRatio = r;
                            exitVar = v;
                        }
                    }
                }
            }

            if (exitVar == null) {
                // exitVar is still null
                if (col.size() == 0) {
                    removeColumn(marker);
                } else {
                    // exitVar = (ClAbstractVariable) col.elements().nextElement();
                    // was the above; instead, let's be sure we do not
                    // pick the objective --01/07/01 gjb
                    for (ClAbstractVariable v : col) {
                        if (v != _objective) {
                            exitVar = v;
                            break;
                        }
                    }
                }
            }

            if (exitVar != null) {
                pivot(marker, exitVar);
            }
        }

        if (rowExpression(marker) != null) {
            removeRow(marker);
        }

        if (eVars != null) {
            for (ClAbstractVariable v : eVars) {
                // FIXGJBNOW != or equals?
                if (v != marker) {
                    removeColumn(v);
                }
            }
        }

        if (cn.isStayConstraint()) {
            if (eVars != null) {
                int size = _stayPlusErrorVars.size();
                for (int i = 0; i < size; i++) {
                    eVars.remove(_stayPlusErrorVars.get(i));
                    eVars.remove(_stayMinusErrorVars.get(i));
                }
            }
        } else if (cn.isEditConstraint()) {
            assert eVars != null : "eVars != null";
            ClEditConstraint cnEdit = (ClEditConstraint) cn;
            ClVariable clv = cnEdit.variable();
            ClEditInfo cei = _editVarMap.get(clv);
            ClSlackVariable clvEditMinus = cei.ClvEditMinus();
            // ClSlackVariable clvEditPlus = cei.ClvEditPlus();
            // the clvEditPlus is a marker variable that is removed elsewhere
            removeColumn(clvEditMinus);
            if (clv != dontRemove) {
                _editVarMap.remove(clv);
            }
        }

        // FIXGJB do the remove at top
        if (eVars != null) {
            _errorVars.remove(eVars);
        }
        marker = null;

        if (_fOptimizeAutomatically) {
            optimize(_objective);
            setExternalVariables();
        }

        return this;
    }

    // Re-solve the current collection of constraints for new values for
    // the constants of the edit variables.
    // DEPRECATED: use suggestValue(...) then resolve()
    // If you must use this, be sure to not use it if you
    // remove an edit variable (or edit constraint) from the middle
    // of a list of edits and then try to resolve with this function
    // (you'll get the wrong answer, because the indices will be wrong
    // in the ClEditInfo objects)
    public final void resolve(List<ClDouble> newEditConstants) throws CLInternalError {
        if (fTraceOn)
            fnenterprint("resolve" + newEditConstants);
        for (Map.Entry<ClVariable, ClEditInfo> entry : _editVarMap.entrySet()) {
            int i = entry.getValue().Index();
            try {
                if (i < newEditConstants.size())
                    suggestValue(entry.getKey(), newEditConstants.get(i).doubleValue());
            } catch (CLException err) {
                throw new CLInternalError("Error during resolve");
            }
        }
        resolve();
    }

    // Convenience function for resolve-s of two variables
    public final void resolve(double x, double y) throws CLInternalError {
        _resolve_pair.get(0).setValue(x);
        _resolve_pair.get(1).setValue(y);
        resolve(_resolve_pair);
    }

    // Re-solve the current collection of constraints, given the new
    // values for the edit variables that have already been
    // suggested (see suggestValue() method)
    public final void resolve() throws CLInternalError {
        if (fTraceOn)
            fnenterprint("resolve()");
        dualOptimize();
        setExternalVariables();
        _infeasibleRows.clear();
        resetStayConstants();
    }

    // Suggest a new value for an edit variable
    // the variable needs to be added as an edit variable
    // and beginEdit() needs to be called before this is called.
    // The tableau will not be solved completely until
    // after resolve() has been called
    public final ClSimplexSolver suggestValue(ClVariable v, double x) throws CLException {
        if (fTraceOn)
            fnenterprint("suggestValue(" + v + ", " + x + ")");
        ClEditInfo cei = _editVarMap.get(v);
        if (cei == null) {
            System.err.println("suggestValue for variable " + v + ", but var is not an edit variable\n");
            throw new CLException();
        }
        ClSlackVariable clvEditPlus = cei.ClvEditPlus();
        ClSlackVariable clvEditMinus = cei.ClvEditMinus();
        double delta = x - cei.PrevEditConstant();
        cei.SetPrevEditConstant(x);
        deltaEditConstant(delta, clvEditPlus, clvEditMinus);
        return this;
    }

    // Control whether optimization and setting of external variables
    // is done automatically or not. By default it is done
    // automatically and solve() never needs to be explicitly
    // called by client code; if setAutosolve is put to false,
    // then solve() needs to be invoked explicitly before using
    // variables' values
    // (Turning off autosolve while adding lots and lots of
    // constraints [ala the addDel test in ClTests] saved
    // about 20% in runtime, from 68sec to 54sec for 900 constraints,
    // with 126 failed adds)
    public final ClSimplexSolver setAutosolve(boolean f) {
        _fOptimizeAutomatically = f;
        return this;
    }

    // Tell whether we are autosolving
    public final boolean FIsAutosolving() {
        return _fOptimizeAutomatically;
    }

    // If autosolving has been turned off, client code needs
    // to explicitly call solve() before accessing variables
    // values
    public final ClSimplexSolver solve() throws CLInternalError {
        if (_fNeedsSolving) {
            optimize(_objective);
            setExternalVariables();
        }
        return this;
    }

    public ClSimplexSolver setEditedValue(ClVariable v, double n) throws CLInternalError {
        if (!containsVariable(v)) {
            v.change_value(n);
            return this;
        }

        if (!CL.approx(n, v.getValue())) {
            addEditVar(v);
            beginEdit();
            try {
                suggestValue(v, n);
            } catch (CLException e) {
                // just added it above, so we shouldn't get an error
                throw new CLInternalError("Error in setEditedValue");
            }
            endEdit();
        }
        return this;
    }

    public final boolean containsVariable(ClVariable v) throws CLInternalError {
        return columnsHasKey(v) || (rowExpression(v) != null);
    }

    public ClSimplexSolver addVar(ClVariable v) throws CLInternalError {
        if (!containsVariable(v)) {
            try {
                addStay(v);
            } catch (RequiredConstraintFailureException e) {
                // cannot have a required failure, since we add w/ weak
                throw new CLInternalError("Error in addVar -- required failure is impossible");
            }
            if (fTraceOn) {
                traceprint("added initial stay on " + v);
            }
        }
        return this;
    }

    // Originally from Michael Noth <noth@cs>
    @Override
    public final String getInternalInfo() {
        StringBuffer retstr = new StringBuffer(super.getInternalInfo());
        retstr.append("\nSolver info:\n");
        retstr.append("Stay Error Variables: ");
        retstr.append(_stayPlusErrorVars.size() + _stayMinusErrorVars.size());
        retstr.append(" (" + _stayPlusErrorVars.size() + " +, ");
        retstr.append(_stayMinusErrorVars.size() + " -)\n");
        retstr.append("Edit Variables: " + _editVarMap.size());
        retstr.append("\n");
        return retstr.toString();
    }

    public final String getDebugInfo() {
        StringBuffer bstr = new StringBuffer(toString());
        bstr.append(getInternalInfo());
        bstr.append("\n");
        return bstr.toString();
    }

    @Override
    public final String toString() {
        StringBuffer bstr = new StringBuffer(super.toString());
        bstr.append("\n_stayPlusErrorVars: ");
        bstr.append(_stayPlusErrorVars);
        bstr.append("\n_stayMinusErrorVars: ");
        bstr.append(_stayMinusErrorVars);

        bstr.append("\n");
        return bstr.toString();
    }

    public Map<ClConstraint, ClAbstractVariable> getConstraintMap() {
        return _markerVars;
    }

    // // END PUBLIC INTERFACE

    // Add the constraint expr=0 to the inequality tableau using an
    // artificial variable. To do this, create an artificial variable
    // av and add av=expr to the inequality tableau, then make av be 0.
    // (Raise an exception if we can't attain av=0.)
    protected final void addWithArtificialVariable(ClLinearExpression expr) throws RequiredConstraintFailureException,
            CLInternalError {
        if (fTraceOn)
            fnenterprint("addWithArtificialVariable: " + expr);

        ClSlackVariable av = new ClSlackVariable(++_artificialCounter, "a");
        ClObjectiveVariable az = new ClObjectiveVariable("az");
        ClLinearExpression azRow = expr.clone();

        if (fTraceOn)
            traceprint("before addRows:\n" + this);

        addRow(az, azRow);
        addRow(av, expr);

        if (fTraceOn)
            traceprint("after addRows:\n" + this);
        optimize(az);

        ClLinearExpression azTableauRow = rowExpression(az);

        if (fTraceOn)
            traceprint("azTableauRow.constant() == " + azTableauRow.constant());

        if (!CL.approx(azTableauRow.constant(), 0.0)) {
            removeRow(az);
            removeColumn(av);
            throw new RequiredConstraintFailureException();
        }

        // See if av is a basic variable
        final ClLinearExpression e = rowExpression(av);

        if (e != null) {
            // find another variable in this row and pivot,
            // so that av becomes parametric
            if (e.isConstant()) {
                // if there isn't another variable in the row
                // then the tableau contains the equation av=0 --
                // just delete av's row
                removeRow(av);
                removeRow(az);
                return;
            }
            ClAbstractVariable entryVar = e.anyPivotableVariable();
            pivot(entryVar, av);
        }
        assert rowExpression(av) == null : "rowExpression(av) == null";
        removeColumn(av);
        removeRow(az);
    }

    // We are trying to add the constraint expr=0 to the appropriate
    // tableau. Try to add expr directly to the tableax without
    // creating an artificial variable. Return true if successful and
    // false if not.
    protected final boolean tryAddingDirectly(ClLinearExpression expr) throws RequiredConstraintFailureException {
        if (fTraceOn)
            fnenterprint("tryAddingDirectly: " + expr);
        final ClAbstractVariable subject = chooseSubject(expr);
        if (subject == null) {
            if (fTraceOn)
                fnexitprint("returning false");
            return false;
        }
        expr.newSubject(subject);
        if (columnsHasKey(subject)) {
            substituteOut(subject, expr);
        }
        addRow(subject, expr);
        if (fTraceOn)
            fnexitprint("returning true");
        return true; // successfully added directly
    }

    // We are trying to add the constraint expr=0 to the tableaux. Try
    // to choose a subject (a variable to become basic) from among the
    // current variables in expr. If expr contains any unrestricted
    // variables, then we must choose an unrestricted variable as the
    // subject. Also, if the subject is new to the solver we won't have
    // to do any substitutions, so we prefer new variables to ones that
    // are currently noted as parametric. If expr contains only
    // restricted variables, if there is a restricted variable with a
    // negative coefficient that is new to the solver we can make that
    // the subject. Otherwise we can't find a subject, so return nil.
    // (In this last case we have to add an artificial variable and use
    // that variable as the subject -- this is done outside this method
    // though.)
    //
    // Note: in checking for variables that are new to the solver, we
    // ignore whether a variable occurs in the objective function, since
    // new slack variables are added to the objective function by
    // 'newExpression:', which is called before this method.
    protected final ClAbstractVariable chooseSubject(ClLinearExpression expr) throws RequiredConstraintFailureException {
        if (fTraceOn)
            fnenterprint("chooseSubject: " + expr);
        ClAbstractVariable subject = null; // the current best subject, if any

        boolean foundUnrestricted = false;
        boolean foundNewRestricted = false;

        final Map<ClAbstractVariable, ClDouble> terms = expr.terms();

        for (Map.Entry<ClAbstractVariable, ClDouble> entry : terms.entrySet()) {
            final ClAbstractVariable v = entry.getKey();
            double c = entry.getValue().doubleValue();

            if (foundUnrestricted) {
                if (!v.isRestricted()) {
                    if (!columnsHasKey(v))
                        return v;
                }
            } else {
                // we haven't found an restricted variable yet
                if (v.isRestricted()) {
                    if (!foundNewRestricted && !v.isDummy() && c < 0.0) {
                        final Set<ClAbstractVariable> col = _columns.get(v);
                        if (col == null || (col.size() == 1 && columnsHasKey(_objective))) {
                            subject = v;
                            foundNewRestricted = true;
                        }
                    }
                } else {
                    subject = v;
                    foundUnrestricted = true;
                }
            }
        }

        if (subject != null)
            return subject;

        double coeff = 0.0;

        for (Map.Entry<ClAbstractVariable, ClDouble> entry : terms.entrySet()) {
            final ClAbstractVariable v = entry.getKey();
            double c = entry.getValue().doubleValue();
            if (!v.isDummy())
                return null; // nope, no luck
            if (!columnsHasKey(v)) {
                subject = v;
                coeff = c;
            }
        }

        if (!CL.approx(expr.constant(), 0.0)) {
            throw new RequiredConstraintFailureException();
        }
        if (coeff > 0.0) {
            expr.multiplyMe(-1);
        }
        return subject;
    }

    // Each of the non-required edits will be represented by an equation
    // of the form
    // v = c + eplus - eminus
    // where v is the variable with the edit, c is the previous edit
    // value, and eplus and eminus are slack variables that hold the
    // error in satisfying the edit constraint. We are about to change
    // something, and we want to fix the constants in the equations
    // representing the edit constraints. If one of eplus and eminus is
    // basic, the other must occur only in the expression for that basic
    // error variable. (They can't both be basic.) Fix the constant in
    // this expression. Otherwise they are both nonbasic. Find all of
    // the expressions in which they occur, and fix the constants in
    // those. See the UIST paper for details.
    // (This comment was for resetEditConstants(), but that is now
    // gone since it was part of the screwey vector-based interface
    // to resolveing. --02/16/99 gjb)
    protected final void deltaEditConstant(double delta, ClAbstractVariable plusErrorVar, ClAbstractVariable minusErrorVar) {
        if (fTraceOn)
            fnenterprint("deltaEditConstant :" + delta + ", " + plusErrorVar + ", " + minusErrorVar);
        ClLinearExpression exprPlus = rowExpression(plusErrorVar);
        if (exprPlus != null) {
            exprPlus.incrementConstant(delta);

            if (exprPlus.constant() < 0.0) {
                _infeasibleRows.add(plusErrorVar);
            }
            return;
        }

        ClLinearExpression exprMinus = rowExpression(minusErrorVar);
        if (exprMinus != null) {
            exprMinus.incrementConstant(-delta);
            if (exprMinus.constant() < 0.0) {
                _infeasibleRows.add(minusErrorVar);
            }
            return;
        }

        Set<ClAbstractVariable> columnVars = _columns.get(minusErrorVar);

        for (ClAbstractVariable basicVar : columnVars) {
            ClLinearExpression expr = rowExpression(basicVar);
            // assert(expr != null, "expr != null" );
            final double c = expr.coefficientFor(minusErrorVar);
            expr.incrementConstant(c * delta);
            if (basicVar.isRestricted() && expr.constant() < 0.0) {
                _infeasibleRows.add(basicVar);
            }
        }
    }

    // We have set new values for the constants in the edit constraints.
    // Re-optimize using the dual simplex algorithm.
    protected final void dualOptimize() throws CLInternalError {
        if (fTraceOn)
            fnenterprint("dualOptimize:");
        final ClLinearExpression zRow = rowExpression(_objective);
        while (!_infeasibleRows.isEmpty()) {
            ClAbstractVariable exitVar = _infeasibleRows.iterator().next();
            _infeasibleRows.remove(exitVar);
            ClAbstractVariable entryVar = null;
            ClLinearExpression expr = rowExpression(exitVar);
            if (expr != null) {
                if (expr.constant() < 0.0) {
                    double ratio = Double.MAX_VALUE;
                    double r;
                    Map<ClAbstractVariable, ClDouble> terms = expr.terms();
                    for (Map.Entry<ClAbstractVariable, ClDouble> entry : terms.entrySet()) {
                        final ClAbstractVariable v = entry.getKey();
                        double c = entry.getValue().doubleValue();
                        if (c > 0.0 && v.isPivotable()) {
                            double zc = zRow.coefficientFor(v);
                            r = zc / c; // FIXGJB r:= zc/c or zero, as ClSymbolicWeight-s
                            if (r < ratio || (CL.approx(r, ratio) && v.hashCode() < entryVar.hashCode())) {
                                entryVar = v;
                                ratio = r;
                            }
                        }
                    }
                    if (ratio == Double.MAX_VALUE) {
                        throw new CLInternalError("ratio == nil (MAX_VALUE) in dualOptimize");
                    }
                    pivot(entryVar, exitVar);
                }
            }
        }
    }

    // Make a new linear expression representing the constraint cn,
    // replacing any basic variables with their defining expressions.
    // Normalize if necessary so that the constant is non-negative. If
    // the constraint is non-required give its error variables an
    // appropriate weight in the objective function.
    protected final ClLinearExpression newExpression(ClConstraint cn, List<ClSlackVariable> eplus_eminus, ClDouble prevEConstant) {
        if (fTraceOn)
            fnenterprint("newExpression: " + cn);
        if (fTraceOn)
            traceprint("cn.isInequality() == " + cn.isInequality());
        if (fTraceOn)
            traceprint("cn.isRequired() == " + cn.isRequired());

        final ClLinearExpression cnExpr = cn.expression();
        ClLinearExpression expr = new ClLinearExpression(cnExpr.constant());
        ClSlackVariable slackVar = new ClSlackVariable();
        // ClDummyVariable dummyVar = new ClDummyVariable();
        ClSlackVariable eminus = new ClSlackVariable();
        ClSlackVariable eplus = new ClSlackVariable();
        final Map<ClAbstractVariable, ClDouble> cnTerms = cnExpr.terms();
        for (Map.Entry<ClAbstractVariable, ClDouble> entry : cnTerms.entrySet()) {
            final ClAbstractVariable v = entry.getKey();
            double c = entry.getValue().doubleValue();
            final ClLinearExpression e = rowExpression(v);
            if (e == null)
                expr.addVariable(v, c);
            else
                expr.addExpression(e, c);
        }

        if (cn.isInequality()) {
            ++_slackCounter;
            slackVar = new ClSlackVariable(_slackCounter, "s");
            expr.setVariable(slackVar, -1);
            _markerVars.put(cn, slackVar);
            if (!cn.isRequired()) {
                ++_slackCounter;
                eminus = new ClSlackVariable(_slackCounter, "em");
                expr.setVariable(eminus, 1.0);
                ClLinearExpression zRow = rowExpression(_objective);
                ClSymbolicWeight sw = cn.strength().getSymbolicWeight().times(cn.weight());
                zRow.setVariable(eminus, sw.asDouble());
                insertErrorVar(cn, eminus);
                noteAddedVariable(eminus, _objective);
            }
        } else {
            // cn is an equality
            if (cn.isRequired()) {
                ++_dummyCounter;
                ClDummyVariable dummyVar = new ClDummyVariable(_dummyCounter, "d");
                expr.setVariable(dummyVar, 1.0);
                _markerVars.put(cn, dummyVar);
                if (fTraceOn)
                    traceprint("Adding dummyVar == d" + _dummyCounter);
            } else {
                ++_slackCounter;
                eplus = new ClSlackVariable(_slackCounter, "ep");
                eminus = new ClSlackVariable(_slackCounter, "em");

                expr.setVariable(eplus, -1.0);
                expr.setVariable(eminus, 1.0);
                _markerVars.put(cn, eplus);
                ClLinearExpression zRow = rowExpression(_objective);
                ClSymbolicWeight sw = cn.strength().getSymbolicWeight().times(cn.weight());
                double swCoeff = sw.asDouble();
                if (swCoeff == 0) {
                    if (fTraceOn)
                        traceprint("sw == " + sw);
                    if (fTraceOn)
                        traceprint("cn == " + cn);
                    if (fTraceOn)
                        traceprint("adding " + eplus + " and " + eminus + " with swCoeff == " + swCoeff);
                }
                zRow.setVariable(eplus, swCoeff);
                noteAddedVariable(eplus, _objective);
                zRow.setVariable(eminus, swCoeff);
                noteAddedVariable(eminus, _objective);
                insertErrorVar(cn, eminus);
                insertErrorVar(cn, eplus);
                if (cn.isStayConstraint()) {
                    _stayPlusErrorVars.add(eplus);
                    _stayMinusErrorVars.add(eminus);
                } else if (cn.isEditConstraint()) {
                    eplus_eminus.add(eplus);
                    eplus_eminus.add(eminus);
                    prevEConstant.setValue(cnExpr.constant());
                }
            }
        }

        if (expr.constant() < 0)
            expr.multiplyMe(-1);

        if (fTraceOn)
            fnexitprint("returning " + expr);
        return expr;
    }

    // Minimize the value of the objective. (The tableau should already
    // be feasible.)
    protected final void optimize(ClObjectiveVariable zVar) throws CLInternalError {
        if (fTraceOn)
            fnenterprint("optimize: " + zVar);
        if (fTraceOn)
            traceprint(this.toString());

        ClLinearExpression zRow = rowExpression(zVar);
        assert zRow != null : "zRow != null";
        ClAbstractVariable entryVar = null;
        ClAbstractVariable exitVar = null;
        while (true) {
            double objectiveCoeff = 0;
            Map<ClAbstractVariable, ClDouble> terms = zRow.terms();
            for (Map.Entry<ClAbstractVariable, ClDouble> entry : terms.entrySet()) {
                final ClAbstractVariable v = entry.getKey();
                double c = entry.getValue().doubleValue();
                // if (v.isPivotable() && c < 0.0 && (entryVar == null || v.hashCode() < entryVar.hashCode())) {
                if (v.isPivotable() && c < objectiveCoeff) {
                    objectiveCoeff = c;
                    entryVar = v;
                    break;
                }
            }
            if (objectiveCoeff >= -_epsilon) // || entryVar == null)
                return;
            if (fTraceOn)
                traceprint("entryVar == " + entryVar + ", objectiveCoeff == " + objectiveCoeff);

            double minRatio = Double.MAX_VALUE;
            Set<ClAbstractVariable> columnVars = _columns.get(entryVar);
            double r = 0.0;
            for (ClAbstractVariable v : columnVars) {
                if (fTraceOn)
                    traceprint("Checking " + v);
                if (v.isPivotable()) {
                    final ClLinearExpression expr = rowExpression(v);
                    double coeff = expr.coefficientFor(entryVar);
                    if (fTraceOn)
                        traceprint("pivotable, coeff = " + coeff);
                    if (coeff < 0.0) {
                        r = -expr.constant() / coeff;
                        if (r < minRatio || (CL.approx(r, minRatio) && v.hashCode() < exitVar.hashCode())) {
                            minRatio = r;
                            exitVar = v;
                        }
                    }
                }
            }
            if (minRatio == Double.MAX_VALUE) {
                throw new CLInternalError("Objective function is unbounded in optimize");
            }
            pivot(entryVar, exitVar);
            if (fTraceOn)
                traceprint(this.toString());
        }
    }

    // Do a pivot. Move entryVar into the basis (i.e. make it a basic variable),
    // and move exitVar out of the basis (i.e., make it a parametric variable)
    protected final void pivot(ClAbstractVariable entryVar, ClAbstractVariable exitVar) throws CLInternalError {

        // the entryVar might be non-pivotable if we're doing a removeConstraint --
        // otherwise it should be a pivotable variable -- enforced at call sites,
        // hopefully

        ClLinearExpression pexpr = removeRow(exitVar);

        pexpr.changeSubject(exitVar, entryVar);
        substituteOut(entryVar, pexpr);
        addRow(entryVar, pexpr);
    }

    // Each of the non-required stays will be represented by an equation
    // of the form
    // v = c + eplus - eminus
    // where v is the variable with the stay, c is the previous value of
    // v, and eplus and eminus are slack variables that hold the error
    // in satisfying the stay constraint. We are about to change
    // something, and we want to fix the constants in the equations
    // representing the stays. If both eplus and eminus are nonbasic
    // they have value 0 in the current solution, meaning the previous
    // stay was exactly satisfied. In this case nothing needs to be
    // changed. Otherwise one of them is basic, and the other must
    // occur only in the expression for that basic error variable.
    // Reset the constant in this expression to 0.
    protected final void resetStayConstants() {
        int size = _stayPlusErrorVars.size();
        for (int i = 0; i < size; i++) {
            ClLinearExpression expr = rowExpression(_stayPlusErrorVars.get(i));
            if (expr == null)
                expr = rowExpression(_stayMinusErrorVars.get(i));
            if (expr != null)
                expr.set_constant(0.0);
        }
    }

    // Set the external variables known to this solver to their appropriate values.
    // Set each external basic variable to its value, and set each
    // external parametric variable to 0. (It isn't clear that we will
    // ever have external parametric variables -- every external
    // variable should either have a stay on it, or have an equation
    // that defines it in terms of other external variables that do have
    // stays. For the moment I'll put this in though.) Variables that
    // are internal to the solver don't actually store values -- their
    // values are just implicit in the tableu -- so we don't need to set
    // them.
    protected final void setExternalVariables() {
        for (ClVariable v : _externalParametricVars) {
            if (_rows.containsKey(v)) {
                System.err.println("Error: variable" + v + " in _externalParametricVars is basic");
                continue;
            }
            v.change_value(0.0);
        }

        for (ClVariable v : _externalRows) {
            ClLinearExpression expr = rowExpression(v);
            v.change_value(expr.constant());
        }

        _fNeedsSolving = false;
    }

    // Protected convenience function to insert an error variable into
    // the _errorVars set, creating the mapping with put as necessary
    protected final void insertErrorVar(ClConstraint cn, ClAbstractVariable var) {
        if (fTraceOn)
            fnenterprint("insertErrorVar:" + cn + ", " + var);

        Set<ClAbstractVariable> cnset = _errorVars.get(var);
        if (cnset == null)
            _errorVars.put(cn, cnset = new HashSet<ClAbstractVariable>());
        cnset.add(var);
    }
} public class ClStrength {
    public static final ClStrength required = new ClStrength("<Required>", 1000, 1000, 1000);

    public static final ClStrength strong = new ClStrength("strong", 1.0, 0.0, 0.0);

    public static final ClStrength medium = new ClStrength("medium", 0.0, 1.0, 0.0);

    public static final ClStrength weak = new ClStrength("weak", 0.0, 0.0, 1.0);

    private String _name;

    private ClSymbolicWeight _symbolicWeight;

    public ClStrength(String name, ClSymbolicWeight symbolicWeight) {
        _name = name;
        _symbolicWeight = symbolicWeight;
    }

    public ClStrength(String name, double w1, double w2, double w3) {
        this(name, new ClSymbolicWeight(w1, w2, w3));
    }

    public boolean isRequired() {
        return (this == required);
    }

    @Override
    public String toString() {
        return getName() + (!isRequired() ? (":" + getSymbolicWeight()) : "");
    }

    public ClSymbolicWeight getSymbolicWeight() {
        return _symbolicWeight;
    }

    public String getName() {
        return _name;
    }

} public class ClVariable extends ClAbstractVariable {

    private double _value;

    private Object _attachedObject;

    public ClVariable(String name, double value) {
        super(name);
        _value = value;
    }

    public ClVariable(String name) {
        super(name);
        _value = 0.0;
    }

    public ClVariable(double value) {
        _value = value;
    }

    public ClVariable() {
        _value = 0.0;
    }

    public ClVariable(long number, String prefix, double value) {
        super(number, prefix);
        _value = value;
    }

    public ClVariable(long number, String prefix) {
        super(number, prefix);
        _value = 0.0;
    }

    @Override
    public boolean isDummy() {
        return false;
    }

    @Override
    public boolean isExternal() {
        return true;
    }

    @Override
    public boolean isPivotable() {
        return false;
    }

    @Override
    public boolean isRestricted() {
        return false;
    }

    @Override
    public String toString() {
        return "[" + name() + ":" + _value + "]";
    }

    public final double getValue() {
        return _value;
    }

    // change the value held -- should *not* use this if the variable is
    // in a solver -- instead use addEditVar() and suggestValue() interface
    public final void setValue(double value) {
        _value = value;
    }

    // permit overriding in subclasses in case something needs to be
    // done when the value is changed by the solver
    // may be called when the value hasn't actually changed -- just
    // means the solver is setting the external variable
    public void change_value(double value) {
        _value = value;
    }

    public void setAttachedObject(Object o) {
        _attachedObject = o;
    }

    public Object getAttachedObject() {
        return _attachedObject;
    }

} public class ConstraintNotFoundException extends CLException {
    public ConstraintNotFoundException() {
        super("Tried to remove a constraint never added to the tableu");
    }
} public class RequiredConstraintFailureException extends CLException {
    public RequiredConstraintFailureException() {
        super("A required constraint cannot be satisfied");
    }
} public class CDA_G {
    public static final Color DARK_GREEN = new Color(0, 160, 0);
    public static final Color DARK_RED = new Color(160, 0, 0);
    public static final Color DARK_BLUE = new Color(0, 0, 160);

    // Constants for size of box around a selectable point
    public static final int SELBOXSIZE = 8;
    public static final int DRAWBOXSIZE = 6;
} public abstract class Constraint {
    public int x, y;

    // Reference to the solver
    protected ClSimplexSolver solver;

    // List of SelPoints being constrained
    public List<SelPoint> selPointList;

    // List of CC's being constrained
    public List<ConstrComponent> ccList;

    // Bounding box of the CC
    public Rectangle bbox;
    // Flag for being selected
    protected boolean isSelected;
    protected boolean isHighlighted;

    // Create a new, empty constraint
    public Constraint(ClSimplexSolver solver) {
        this.solver = solver;
        selPointList = new ArrayList<SelPoint>(10);
        ccList = new ArrayList<ConstrComponent>(10);

        isSelected = false;
        isHighlighted = false;
        bbox = new Rectangle(0, 0, 0, 0);
    }

    // Add a SelPoint to the list of SelPoints being constrained
    public void addSelPoint(SelPoint sp) {
        // Make sure a given SelPoint can only appear once
        if (!selPointList.contains(sp))
            selPointList.add(sp);
    }

    // Add a CC to the list of CC's being constrained
    public void addCC(ConstrComponent c) {
        if (!ccList.contains(c))
            ccList.add(c);
    }

    // Add a vector of SelPoints to list
    public void addSelPoint(List<SelPoint> v) {
        for (SelPoint sp : v) {
            addSelPoint(sp);
        }
    }

    // Add constraints to solver, creating them if necessary.
    public abstract void addConstraints();

    // Remove constraints from solver
    public abstract void removeConstraints();

    // Draw the representation of the constraint
    public abstract void draw(Graphics g);

    // Method to replace all instances of the given SelPoint with another.
    // It is assumed that any SelPoint-internal constraints have already
    // beeen established.
    // This method should retract/extend constraints as appropriate to
    // each subclass, using the new point.
    public abstract void replaceSelPoint(SelPoint oldsp, SelPoint newsp);

    // Method to notify the constraint that a given CC is going away.
    // A constraint can ignore this or choose to remove constraints,
    // as appropriate. Default version does nothing.
    public void notifyCCRemoval(ConstrComponent c) {
    }

    // Method to notify the constraint that a given SelPoint is going away.
    // A constraint can ignore this or choose to remove constraints, as
    // appropriate. Default version does nothing.
    public void notifySPRemoval(SelPoint sp) {
    }

    // Method to notify the constraint that a bounding box of a CC it is
    // interested in has changed. Mainly of use to relational constraints.
    // Default behavior is to do nothing.
    public void notifyCCBBoxChange(ConstrComponent c) {
    }

    // Method that determines if the constraint can be discarded.
    // This is needed as a call to replaceSelPoint or notifyCCRemoval
    // could conceiveably render a constraint obj. no longer relevant.
    public abstract boolean canDiscard();

    // Clean up function. By default, removes all constraints and clears out
    // the list of interested CC's and SP's.
    public void cleanUp() {
        removeConstraints();

        for (SelPoint sp : selPointList) {
            sp.removeInterestedConstr(this);
        }
        selPointList.clear();

        for (ConstrComponent cc : ccList) {
            cc.removeInterestedConstr(this);
        }
        ccList.clear();
    }

    // Method for highlighting as the mouse moves
    // Just highlights the bbox of the constraint
    public void highlight(Point p, boolean isShiftDown) {
        if (bbox.contains(p) && isShiftDown)
            isHighlighted = true;
        else
            isHighlighted = false;
    }

    public void highlight(Rectangle r) {
        if ((bbox.x >= r.x) && (bbox.y >= r.y) && ((bbox.x + bbox.width) <= (r.x + r.width))
                && ((bbox.y + bbox.height) <= (r.y + r.height)))
            isHighlighted = true;
        else
            isHighlighted = false;
    }

    public void unselect() {
        isSelected = false;
    }

    public boolean getisSelected() {
        return isSelected;
    }

    public void setisSelected(boolean state) {
        isSelected = state;
    }

} public class ClEditConstraint extends ClEditOrStayConstraint {

    public ClEditConstraint(ClVariable clv, ClStrength strength, double weight) {
        super(clv, strength, weight);
    }

    public ClEditConstraint(ClVariable clv, ClStrength strength) {
        super(clv, strength);
    }

    public ClEditConstraint(ClVariable clv) {
        super(clv);
    }

    @Override
    public boolean isEditConstraint() {
        return true;
    }

    @Override
    public String toString() {
        return "edit" + super.toString();
    }

} public class ClLinearInequality extends ClLinearConstraint {

    public ClLinearInequality(ClLinearExpression cle, ClStrength strength, double weight) {
        super(cle, strength, weight);
    }

    public ClLinearInequality(ClLinearExpression cle, ClStrength strength) {
        super(cle, strength);
    }

    public ClLinearInequality(ClLinearExpression cle) {
        super(cle);
    }

    public ClLinearInequality(ClVariable clv1, byte op_enum, ClVariable clv2, ClStrength strength, double weight)
            throws CLInternalError {
        super(new ClLinearExpression(clv2), strength, weight);
        if (op_enum == CL.GEQ) {
            _expression.multiplyMe(-1.0);
            _expression.addVariable(clv1);
        } else if (op_enum == CL.LEQ) {
            _expression.addVariable(clv1, -1.0);
        } else
            // the operator was invalid
            throw new CLInternalError("Invalid operator in ClLinearInequality constructor");
    }

    public ClLinearInequality(ClVariable clv1, byte op_enum, ClVariable clv2, ClStrength strength) throws CLInternalError {
        this(clv1, op_enum, clv2, strength, 1.0);
    }

    public ClLinearInequality(ClVariable clv1, byte op_enum, ClVariable clv2) throws CLInternalError {
        this(clv1, op_enum, clv2, ClStrength.required, 1.0);
    }

    public ClLinearInequality(ClVariable clv, byte op_enum, double val, ClStrength strength, double weight)
            throws CLInternalError {
        super(new ClLinearExpression(val), strength, weight);
        if (op_enum == CL.GEQ) {
            _expression.multiplyMe(-1.0);
            _expression.addVariable(clv);
        } else if (op_enum == CL.LEQ) {
            _expression.addVariable(clv, -1.0);
        } else
            // the operator was invalid
            throw new CLInternalError("Invalid operator in ClLinearInequality constructor");
    }

    public ClLinearInequality(ClVariable clv, byte op_enum, double val, ClStrength strength) throws CLInternalError {
        this(clv, op_enum, val, strength, 1.0);
    }

    public ClLinearInequality(ClVariable clv, byte op_enum, double val) throws CLInternalError {
        this(clv, op_enum, val, ClStrength.required, 1.0);
    }

    public ClLinearInequality(ClLinearExpression cle1, byte op_enum, ClLinearExpression cle2, ClStrength strength, double weight)
            throws CLInternalError {
        super(cle2.clone(), strength, weight);
        if (op_enum == CL.GEQ) {
            _expression.multiplyMe(-1.0);
            _expression.addExpression(cle1);
        } else if (op_enum == CL.LEQ) {
            _expression.addExpression(cle1, -1.0);
        } else
            // the operator was invalid
            throw new CLInternalError("Invalid operator in ClLinearInequality constructor");
    }

    public ClLinearInequality(ClLinearExpression cle1, byte op_enum, ClLinearExpression cle2, ClStrength strength)
            throws CLInternalError {
        this(cle1, op_enum, cle2, strength, 1.0);
    }

    public ClLinearInequality(ClLinearExpression cle1, byte op_enum, ClLinearExpression cle2) throws CLInternalError {
        this(cle1, op_enum, cle2, ClStrength.required, 1.0);
    }

    public ClLinearInequality(ClAbstractVariable clv, byte op_enum, ClLinearExpression cle, ClStrength strength, double weight)
            throws CLInternalError {
        super(cle.clone(), strength, weight);
        if (op_enum == CL.GEQ) {
            _expression.multiplyMe(-1.0);
            _expression.addVariable(clv);
        } else if (op_enum == CL.LEQ) {
            _expression.addVariable(clv, -1.0);
        } else
            // the operator was invalid
            throw new CLInternalError("Invalid operator in ClLinearInequality constructor");
    }

    public ClLinearInequality(ClAbstractVariable clv, byte op_enum, ClLinearExpression cle, ClStrength strength)
            throws CLInternalError {
        this(clv, op_enum, cle, strength, 1.0);
    }

    public ClLinearInequality(ClAbstractVariable clv, byte op_enum, ClLinearExpression cle) throws CLInternalError {
        this(clv, op_enum, cle, ClStrength.required, 1.0);
    }

    public ClLinearInequality(ClLinearExpression cle, byte op_enum, ClAbstractVariable clv, ClStrength strength, double weight)
            throws CLInternalError {
        super(cle.clone(), strength, weight);
        if (op_enum == CL.LEQ) {
            _expression.multiplyMe(-1.0);
            _expression.addVariable(clv);
        } else if (op_enum == CL.GEQ) {
            _expression.addVariable(clv, -1.0);
        } else
            // the operator was invalid
            throw new CLInternalError("Invalid operator in ClLinearInequality constructor");
    }

    public ClLinearInequality(ClLinearExpression cle, byte op_enum, ClAbstractVariable clv, ClStrength strength)
            throws CLInternalError {
        this(cle, op_enum, clv, strength, 1.0);
    }

    public ClLinearInequality(ClLinearExpression cle, byte op_enum, ClAbstractVariable clv) throws CLInternalError {
        this(cle, op_enum, clv, ClStrength.required, 1.0);
    }

    @Override
    public final boolean isInequality() {
        return true;
    }

    @Override
    public final String toString() {
        return super.toString() + " >= 0 )";
    }
} public class ClStayConstraint extends ClEditOrStayConstraint {

    public ClStayConstraint(ClVariable var, ClStrength strength, double weight) {
        super(var, strength, weight);
    }

    public ClStayConstraint(ClVariable var, ClStrength strength) {
        super(var, strength, 1.0);
    }

    public ClStayConstraint(ClVariable var) {
        super(var, ClStrength.weak, 1.0);
    }

    @Override
    public boolean isStayConstraint() {
        return true;
    }

    @Override
    public String toString() {
        return "stay " + super.toString();
    }

}
import org.klomp.cassowary.awt.CDA_G;
import org.klomp.cassowary.awt.constraint.Constraint;
import org.klomp.cassowary.clconstraint.ClEditConstraint;
import org.klomp.cassowary.clconstraint.ClLinearInequality;
import org.klomp.cassowary.clconstraint.ClStayConstraint;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import org.klomp.cassowary.CL;
import org.klomp.cassowary.CLInternalError;
import org.klomp.cassowary.ClSimplexSolver;
import org.klomp.cassowary.ClStrength;
import org.klomp.cassowary.ClVariable;
import org.klomp.cassowary.ConstraintNotFoundException;
import org.klomp.cassowary.RequiredConstraintFailureException;
/*
 * Selectable Point class
 * Consists of a Point and a flag indicating if it is currently selected.
 *
 * SelPoints also have a list of CC's and constraint objs that care about
 * them in some way.  For CC's, the interest will usually be owning/sharing
 * the SelPoint.  For constraint objs, the interest will usually be a
 * constraint on the SelPoint.
 *
 * There is also an owner field that indicates which CC, if any, actually
 * owns the SelPoint (IE is responsible for the actual obj, not just refs)
 *
 * $Id: SelPoint.java,v 1.4 1999/12/16 02:09:59 gjb Exp $
 *
 */

package org.klomp.cassowary.awt.component;



public class SelPoint implements Cloneable {
    public int x, y;
    public boolean isHighlighted;

    boolean isSelected;

    public int id; // Unique ID of each SelPoint
    private static int nextID = 0;

    // Which CC(s) have an interest in this SelPoint?
    protected List<ConstrComponent> interCC;
    // Which constraint objs. have an interest in this SelPoint?
    protected List<Constraint> interConstr;

    // Which CC owns this SelPoint (IE is in charge of deleting it)
    protected ConstrComponent owner;

    // Reference to the solver
    protected ClSimplexSolver solver;
    // Edit constraints held by this SelPoint
    protected ClEditConstraint editX, editY;
    // Constraint variables for X, Y position
    protected ClVariable clX, clY;
    // Stay constraints associated with point
    protected ClStayConstraint stayX, stayY;
    // Constraints associated with left, top window edges
    protected ClLinearInequality leftBorderConstraint, topBorderConstraint;