// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include "qgraphicsanchorlayout_p.h"

#include <QtWidgets/qwidget.h>
#include <QtWidgets/qapplication.h>
#include <QtCore/qstack.h>

#ifdef QT_DEBUG
#include <QtCore/qfile.h>
#endif

#include <numeric>

QT_BEGIN_NAMESPACE

using namespace Qt::StringLiterals;

// To ensure that all variables inside the simplex solver are non-negative,
// we limit the size of anchors in the interval [-limit, limit]. Then before
// sending them to the simplex solver we add "limit" as an offset, so that
// they are actually calculated in the interval [0, 2 * limit]
// To avoid numerical errors in platforms where we use single precision,
// we use a tighter limit for the variables range.
const qreal g_offset = (sizeof(qreal) == sizeof(double)) ? QWIDGETSIZE_MAX : QWIDGETSIZE_MAX / 32;

QGraphicsAnchorPrivate::QGraphicsAnchorPrivate(int version)
    : QObjectPrivate(version), layoutPrivate(nullptr), data(nullptr),
      sizePolicy(QSizePolicy::Fixed), preferredSize(0),
      hasSize(true)
{
}

QGraphicsAnchorPrivate::~QGraphicsAnchorPrivate()
{
    if (data) {
        // The QGraphicsAnchor was already deleted at this moment. We must clean
        // the dangling pointer to avoid double deletion in the AnchorData dtor.
        data->graphicsAnchor = nullptr;

        layoutPrivate->removeAnchor(data->from, data->to);
    }
}

void QGraphicsAnchorPrivate::setSizePolicy(QSizePolicy::Policy policy)
{
    if (sizePolicy != policy) {
        sizePolicy = policy;
        layoutPrivate->q_func()->invalidate();
    }
}

void QGraphicsAnchorPrivate::setSpacing(qreal value)
{
    if (!data) {
        qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
        return;
    }

    if (hasSize && (preferredSize == value))
        return;

    // The anchor has an user-defined size
    hasSize = true;
    preferredSize = value;

    layoutPrivate->q_func()->invalidate();
}

void QGraphicsAnchorPrivate::unsetSpacing()
{
    if (!data) {
        qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
        return;
    }

    // Return to standard direction
    hasSize = false;

    layoutPrivate->q_func()->invalidate();
}

qreal QGraphicsAnchorPrivate::spacing() const
{
    if (!data) {
        qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
        return 0;
    }

    return preferredSize;
}


static void applySizePolicy(QSizePolicy::Policy policy,
                            qreal minSizeHint, qreal prefSizeHint, qreal maxSizeHint,
                            qreal *minSize, qreal *prefSize,
                            qreal *maxSize)
{
    // minSize, prefSize and maxSize are initialized
    // with item's preferred Size: this is QSizePolicy::Fixed.
    //
    // Then we check each flag to find the resultant QSizePolicy,
    // according to the following table:
    //
    //      constant               value
    // QSizePolicy::Fixed            0
    // QSizePolicy::Minimum       GrowFlag
    // QSizePolicy::Maximum       ShrinkFlag
    // QSizePolicy::Preferred     GrowFlag | ShrinkFlag
    // QSizePolicy::Ignored       GrowFlag | ShrinkFlag | IgnoreFlag

    if (policy & QSizePolicy::ShrinkFlag)
        *minSize = minSizeHint;
    else
        *minSize = prefSizeHint;

    if (policy & QSizePolicy::GrowFlag)
        *maxSize = maxSizeHint;
    else
        *maxSize = prefSizeHint;

    // Note that these two initializations are affected by the previous flags
    if (policy & QSizePolicy::IgnoreFlag)
        *prefSize = *minSize;
    else
        *prefSize = prefSizeHint;
}

AnchorData::~AnchorData()
{
    if (graphicsAnchor) {
        // Remove reference to ourself to avoid double removal in
        // QGraphicsAnchorPrivate dtor.
        QGraphicsAnchorPrivate::get(graphicsAnchor)->data = nullptr;

        delete graphicsAnchor;
    }
}


void AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo)
{
    QSizePolicy::Policy policy;
    qreal minSizeHint;
    qreal prefSizeHint;
    qreal maxSizeHint;

    if (item) {
        // It is an internal anchor, fetch size information from the item
        if (isLayoutAnchor) {
            minSize = 0;
            prefSize = 0;
            maxSize = QWIDGETSIZE_MAX;
            if (isCenterAnchor)
                maxSize /= 2;

            minPrefSize = prefSize;
            maxPrefSize = maxSize;
            return;
        } else {
            if (!isVertical) {
                policy = item->sizePolicy().horizontalPolicy();
                minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).width();
                prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).width();
                maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).width();
            } else {
                policy = item->sizePolicy().verticalPolicy();
                minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).height();
                prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).height();
                maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).height();
            }

            if (isCenterAnchor) {
                minSizeHint /= 2;
                prefSizeHint /= 2;
                maxSizeHint /= 2;
            }
        }
    } else {
        // It is a user-created anchor, fetch size information from the associated QGraphicsAnchor
        Q_ASSERT(graphicsAnchor);
        QGraphicsAnchorPrivate *anchorPrivate = QGraphicsAnchorPrivate::get(graphicsAnchor);

        // Policy, min and max sizes are straightforward
        policy = anchorPrivate->sizePolicy;
        minSizeHint = 0;
        maxSizeHint = QWIDGETSIZE_MAX;

        // Preferred Size
        if (anchorPrivate->hasSize) {
            // Anchor has user-defined size
            prefSizeHint = anchorPrivate->preferredSize;
        } else if (styleInfo) {
            // Fetch size information from style
            const Qt::Orientation orient = QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge);
            qreal s = styleInfo->defaultSpacing(orient);
            if (s < 0) {
                QSizePolicy::ControlType controlTypeFrom = from->m_item->sizePolicy().controlType();
                QSizePolicy::ControlType controlTypeTo = to->m_item->sizePolicy().controlType();
                s = styleInfo->perItemSpacing(controlTypeFrom, controlTypeTo, orient);

                // ### Currently we do not support negative anchors inside the graph.
                // To avoid those being created by a negative style spacing, we must
                // make this test.
                if (s < 0)
                    s = 0;
            }
            prefSizeHint = s;
        } else {
            prefSizeHint = 0;
        }
    }

    // Fill minSize, prefSize and maxSize based on policy and sizeHints
    applySizePolicy(policy, minSizeHint, prefSizeHint, maxSizeHint,
                    &minSize, &prefSize, &maxSize);

    minPrefSize = prefSize;
    maxPrefSize = maxSize;

    // Set the anchor effective sizes to preferred.
    //
    // Note: The idea here is that all items should remain at their
    // preferred size unless where that's impossible.  In cases where
    // the item is subject to restrictions (anchored to the layout
    // edges, for instance), the simplex solver will be run to
    // recalculate and override the values we set here.
    sizeAtMinimum = prefSize;
    sizeAtPreferred = prefSize;
    sizeAtMaximum = prefSize;
}

void ParallelAnchorData::updateChildrenSizes()
{
    firstEdge->sizeAtMinimum = sizeAtMinimum;
    firstEdge->sizeAtPreferred = sizeAtPreferred;
    firstEdge->sizeAtMaximum = sizeAtMaximum;

    if (secondForward()) {
        secondEdge->sizeAtMinimum = sizeAtMinimum;
        secondEdge->sizeAtPreferred = sizeAtPreferred;
        secondEdge->sizeAtMaximum = sizeAtMaximum;
    } else {
        secondEdge->sizeAtMinimum = -sizeAtMinimum;
        secondEdge->sizeAtPreferred = -sizeAtPreferred;
        secondEdge->sizeAtMaximum = -sizeAtMaximum;
    }

    firstEdge->updateChildrenSizes();
    secondEdge->updateChildrenSizes();
}

/*
  \internal

  Initialize the parallel anchor size hints using the sizeHint information from
  its children.

  Note that parallel groups can lead to unfeasibility, so during calculation, we can
  find out one unfeasibility. Because of that this method return boolean. This can't
  happen in sequential, so there the method is void.
 */
bool ParallelAnchorData::calculateSizeHints()
{
    // Normalize second child sizes.
    // A negative anchor of sizes min, minPref, pref, maxPref and max, is equivalent
    // to a forward anchor of sizes -max, -maxPref, -pref, -minPref, -min
    qreal secondMin;
    qreal secondMinPref;
    qreal secondPref;
    qreal secondMaxPref;
    qreal secondMax;

    if (secondForward()) {
        secondMin = secondEdge->minSize;
        secondMinPref = secondEdge->minPrefSize;
        secondPref = secondEdge->prefSize;
        secondMaxPref = secondEdge->maxPrefSize;
        secondMax = secondEdge->maxSize;
    } else {
        secondMin = -secondEdge->maxSize;
        secondMinPref = -secondEdge->maxPrefSize;
        secondPref = -secondEdge->prefSize;
        secondMaxPref = -secondEdge->minPrefSize;
        secondMax = -secondEdge->minSize;
    }

    minSize = qMax(firstEdge->minSize, secondMin);
    maxSize = qMin(firstEdge->maxSize, secondMax);

    // This condition means that the maximum size of one anchor being simplified is smaller than
    // the minimum size of the other anchor. The consequence is that there won't be a valid size
    // for this parallel setup.
    if (minSize > maxSize) {
        return false;
    }

    // Preferred size calculation
    // The calculation of preferred size is done as follows:
    //
    // 1) Check whether one of the child anchors is the layout structural anchor
    //    If so, we can simply copy the preferred information from the other child,
    //    after bounding it to our minimum and maximum sizes.
    //    If not, then we proceed with the actual calculations.
    //
    // 2) The whole algorithm for preferred size calculation is based on the fact
    //    that, if a given anchor cannot remain at its preferred size, it'd rather
    //    grow than shrink.
    //
    //    What happens though is that while this affirmative is true for simple
    //    anchors, it may not be true for sequential anchors that have one or more
    //    reversed anchors inside it. That happens because when a sequential anchor
    //    grows, any reversed anchors inside it may be required to shrink, something
    //    we try to avoid, as said above.
    //
    //    To overcome this, besides their actual preferred size "prefSize", each anchor
    //    exports what we call "minPrefSize" and "maxPrefSize". These two values define
    //    a surrounding interval where, if required to move, the anchor would rather
    //    remain inside.
    //
    //    For standard anchors, this area simply represents the region between
    //    prefSize and maxSize, which makes sense since our first affirmation.
    //    For composed anchors, these values are calculated as to reduce the global
    //    "damage", that is, to reduce the total deviation and the total amount of
    //    anchors that had to shrink.

    if (firstEdge->isLayoutAnchor) {
        prefSize = qBound(minSize, secondPref, maxSize);
        minPrefSize = qBound(minSize, secondMinPref, maxSize);
        maxPrefSize = qBound(minSize, secondMaxPref, maxSize);
    } else if (secondEdge->isLayoutAnchor) {
        prefSize = qBound(minSize, firstEdge->prefSize, maxSize);
        minPrefSize = qBound(minSize, firstEdge->minPrefSize, maxSize);
        maxPrefSize = qBound(minSize, firstEdge->maxPrefSize, maxSize);
    } else {
        // Calculate the intersection between the "preferred" regions of each child
        const qreal lowerBoundary =
            qBound(minSize, qMax(firstEdge->minPrefSize, secondMinPref), maxSize);
        const qreal upperBoundary =
            qBound(minSize, qMin(firstEdge->maxPrefSize, secondMaxPref), maxSize);
        const qreal prefMean =
            qBound(minSize, (firstEdge->prefSize + secondPref) / 2, maxSize);

        if (lowerBoundary < upperBoundary) {
            // If there is an intersection between the two regions, this intersection
            // will be used as the preferred region of the parallel anchor itself.
            // The preferred size will be the bounded average between the two preferred
            // sizes.
            prefSize = qBound(lowerBoundary, prefMean, upperBoundary);
            minPrefSize = lowerBoundary;
            maxPrefSize = upperBoundary;
        } else {
            // If there is no intersection, we have to attribute "damage" to at least
            // one of the children. The minimum total damage is achieved in points
            // inside the region that extends from (1) the upper boundary of the lower
            // region to (2) the lower boundary of the upper region.
            // Then, we expose this region as _our_ preferred region and once again,
            // use the bounded average as our preferred size.
            prefSize = qBound(upperBoundary, prefMean, lowerBoundary);
            minPrefSize = upperBoundary;
            maxPrefSize = lowerBoundary;
        }
    }

    // See comment in AnchorData::refreshSizeHints() about sizeAt* values
    sizeAtMinimum = prefSize;
    sizeAtPreferred = prefSize;
    sizeAtMaximum = prefSize;

    return true;
}

/*!
    \internal
    returns the factor in the interval [-1, 1].
    -1 is at Minimum
     0 is at Preferred
     1 is at Maximum
*/
static QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> getFactor(qreal value, qreal min,
                                                                      qreal minPref, qreal pref,
                                                                      qreal maxPref, qreal max)
{
    QGraphicsAnchorLayoutPrivate::Interval interval;
    qreal lower;
    qreal upper;

    if (value < minPref) {
        interval = QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred;
        lower = min;
        upper = minPref;
    } else if (value < pref) {
        interval = QGraphicsAnchorLayoutPrivate::MinPreferredToPreferred;
        lower = minPref;
        upper = pref;
    } else if (value < maxPref) {
        interval = QGraphicsAnchorLayoutPrivate::PreferredToMaxPreferred;
        lower = pref;
        upper = maxPref;
    } else {
        interval = QGraphicsAnchorLayoutPrivate::MaxPreferredToMaximum;
        lower = maxPref;
        upper = max;
    }

    qreal progress;
    if (upper == lower) {
        progress = 0;
    } else {
        progress = (value - lower) / (upper - lower);
    }

    return qMakePair(interval, progress);
}

static qreal interpolate(const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> &factor,
                         qreal min, qreal minPref, qreal pref, qreal maxPref, qreal max)
{
    qreal lower = 0;
    qreal upper = 0;

    switch (factor.first) {
    case QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred:
        lower = min;
        upper = minPref;
        break;
    case QGraphicsAnchorLayoutPrivate::MinPreferredToPreferred:
        lower = minPref;
        upper = pref;
        break;
    case QGraphicsAnchorLayoutPrivate::PreferredToMaxPreferred:
        lower = pref;
        upper = maxPref;
        break;
    case QGraphicsAnchorLayoutPrivate::MaxPreferredToMaximum:
        lower = maxPref;
        upper = max;
        break;
    }

    return lower + factor.second * (upper - lower);
}

void SequentialAnchorData::updateChildrenSizes()
{
    // Band here refers if the value is in the Minimum To Preferred
    // band (the lower band) or the Preferred To Maximum (the upper band).

    const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> minFactor =
        getFactor(sizeAtMinimum, minSize, minPrefSize, prefSize, maxPrefSize, maxSize);
    const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> prefFactor =
        getFactor(sizeAtPreferred, minSize, minPrefSize, prefSize, maxPrefSize, maxSize);
    const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> maxFactor =
        getFactor(sizeAtMaximum, minSize, minPrefSize, prefSize, maxPrefSize, maxSize);

    // XXX This is not safe if Vertex simplification takes place after the sequential
    // anchor is created. In that case, "prev" will be a group-vertex, different from
    // "from" or "to", that _contains_ one of them.
    AnchorVertex *prev = from;

    for (int i = 0; i < m_edges.count(); ++i) {
        AnchorData *e = m_edges.at(i);

        const bool edgeIsForward = (e->from == prev);
        if (edgeIsForward) {
            e->sizeAtMinimum = interpolate(minFactor, e->minSize, e->minPrefSize,
                                           e->prefSize, e->maxPrefSize, e->maxSize);
            e->sizeAtPreferred = interpolate(prefFactor, e->minSize, e->minPrefSize,
                                           e->prefSize, e->maxPrefSize, e->maxSize);
            e->sizeAtMaximum = interpolate(maxFactor, e->minSize, e->minPrefSize,
                                           e->prefSize, e->maxPrefSize, e->maxSize);
            prev = e->to;
        } else {
            Q_ASSERT(prev == e->to);
            e->sizeAtMinimum = interpolate(minFactor, e->maxSize, e->maxPrefSize,
                                           e->prefSize, e->minPrefSize, e->minSize);
            e->sizeAtPreferred = interpolate(prefFactor, e->maxSize, e->maxPrefSize,
                                           e->prefSize, e->minPrefSize, e->minSize);
            e->sizeAtMaximum = interpolate(maxFactor, e->maxSize, e->maxPrefSize,
                                           e->prefSize, e->minPrefSize, e->minSize);
            prev = e->from;
        }

        e->updateChildrenSizes();
    }
}

void SequentialAnchorData::calculateSizeHints()
{
    minSize = 0;
    prefSize = 0;
    maxSize = 0;
    minPrefSize = 0;
    maxPrefSize = 0;

    AnchorVertex *prev = from;

    for (int i = 0; i < m_edges.count(); ++i) {
        AnchorData *edge = m_edges.at(i);

        const bool edgeIsForward = (edge->from == prev);
        if (edgeIsForward) {
            minSize += edge->minSize;
            prefSize += edge->prefSize;
            maxSize += edge->maxSize;
            minPrefSize += edge->minPrefSize;
            maxPrefSize += edge->maxPrefSize;
            prev = edge->to;
        } else {
            Q_ASSERT(prev == edge->to);
            minSize -= edge->maxSize;
            prefSize -= edge->prefSize;
            maxSize -= edge->minSize;
            minPrefSize -= edge->maxPrefSize;
            maxPrefSize -= edge->minPrefSize;
            prev = edge->from;
        }
    }

    // See comment in AnchorData::refreshSizeHints() about sizeAt* values
    sizeAtMinimum = prefSize;
    sizeAtPreferred = prefSize;
    sizeAtMaximum = prefSize;
}

#ifdef QT_DEBUG
void AnchorData::dump(int indent) {
    if (type == Parallel) {
        qDebug("%*s type: parallel:", indent, "");
        ParallelAnchorData *p = static_cast<ParallelAnchorData *>(this);
        p->firstEdge->dump(indent+2);
        p->secondEdge->dump(indent+2);
    } else if (type == Sequential) {
        SequentialAnchorData *s = static_cast<SequentialAnchorData *>(this);
        int kids = s->m_edges.count();
        qDebug("%*s type: sequential(%d):", indent, "", kids);
        for (int i = 0; i < kids; ++i) {
            s->m_edges.at(i)->dump(indent+2);
        }
    } else {
        qDebug("%*s type: Normal:", indent, "");
    }
}

#endif

QSimplexConstraint *GraphPath::constraint(const GraphPath &path) const
{
    // Calculate
    QSet<AnchorData *> cPositives;
    QSet<AnchorData *> cNegatives;
    QSet<AnchorData *> intersection;

    cPositives = positives + path.negatives;
    cNegatives = negatives + path.positives;

    intersection = cPositives & cNegatives;

    cPositives -= intersection;
    cNegatives -= intersection;

    // Fill
    QSimplexConstraint *c = new QSimplexConstraint;
    QSet<AnchorData *>::iterator i;
    for (i = cPositives.begin(); i != cPositives.end(); ++i)
        c->variables.insert(*i, 1.0);

    for (i = cNegatives.begin(); i != cNegatives.end(); ++i)
        c->variables.insert(*i, -1.0);

    return c;
}

#ifdef QT_DEBUG
QString GraphPath::toString() const
{
    QString string("Path: "_L1);
    for (AnchorData *edge : positives)
        string += QString::fromLatin1(" (+++) %1").arg(edge->toString());

    for (AnchorData *edge : negatives)
        string += QString::fromLatin1(" (---) %1").arg(edge->toString());

    return string;
}
#endif

QGraphicsAnchorLayoutPrivate::QGraphicsAnchorLayoutPrivate()
    : calculateGraphCacheDirty(true), styleInfoDirty(true)
{
}

Qt::AnchorPoint QGraphicsAnchorLayoutPrivate::oppositeEdge(Qt::AnchorPoint edge)
{
    switch (edge) {
    case Qt::AnchorLeft:
        edge = Qt::AnchorRight;
        break;
    case Qt::AnchorRight:
        edge = Qt::AnchorLeft;
        break;
    case Qt::AnchorTop:
        edge = Qt::AnchorBottom;
        break;
    case Qt::AnchorBottom:
        edge = Qt::AnchorTop;
        break;
    default:
        break;
    }
    return edge;
}


/*!
    \internal

    Adds \a newAnchor to the graph.

    Returns the newAnchor itself if it could be added without further changes to the graph. If a
    new parallel anchor had to be created, then returns the new parallel anchor. If a parallel anchor
    had to be created and it results in an unfeasible setup, \a feasible is set to false, otherwise
    true.

    Note that in the case a new parallel anchor is created, it might also take over some constraints
    from its children anchors.
*/
AnchorData *QGraphicsAnchorLayoutPrivate::addAnchorMaybeParallel(AnchorData *newAnchor, bool *feasible)
{
    const Qt::Orientation orientation = newAnchor->isVertical ? Qt::Vertical : Qt::Horizontal;
    Graph<AnchorVertex, AnchorData> &g = graph[orientation];
    *feasible = true;

    // If already exists one anchor where newAnchor is supposed to be, we create a parallel
    // anchor.
    if (AnchorData *oldAnchor = g.takeEdge(newAnchor->from, newAnchor->to)) {
        ParallelAnchorData *parallel = new ParallelAnchorData(oldAnchor, newAnchor);

        // The parallel anchor will "replace" its children anchors in
        // every center constraint that they appear.

        // ### If the dependent (center) anchors had reference(s) to their constraints, we
        // could avoid traversing all the itemCenterConstraints.
        QList<QSimplexConstraint *> &constraints = itemCenterConstraints[orientation];

        AnchorData *children[2] = { oldAnchor, newAnchor };
        QList<QSimplexConstraint *> *childrenConstraints[2] = { &parallel->m_firstConstraints,
                                                                &parallel->m_secondConstraints };

        for (int i = 0; i < 2; ++i) {
            AnchorData *child = children[i];
            QList<QSimplexConstraint *> *childConstraints = childrenConstraints[i];

            // We need to fix the second child constraints if the parallel group will have the
            // opposite direction of the second child anchor. For the point of view of external
            // entities, this anchor was reversed. So if at some point we say that the parallel
            // has a value of 20, this mean that the second child (when reversed) will be
            // assigned -20.
            const bool needsReverse = i == 1 && !parallel->secondForward();

            if (!child->isCenterAnchor)
                continue;

            parallel->isCenterAnchor = true;

            for (int j = 0; j < constraints.count(); ++j) {
                QSimplexConstraint *c = constraints[j];
                if (c->variables.contains(child)) {
                    childConstraints->append(c);
                    qreal v = c->variables.take(child);
                    if (needsReverse)
                        v *= -1;
                    c->variables.insert(parallel, v);
                }
            }
        }

        // At this point we can identify that the parallel anchor is not feasible, e.g. one
        // anchor minimum size is bigger than the other anchor maximum size.
        *feasible = parallel->calculateSizeHints();
        newAnchor = parallel;
    }

    g.createEdge(newAnchor->from, newAnchor->to, newAnchor);
    return newAnchor;
}

/*!
    \internal

    Takes the sequence of vertices described by (\a before, \a vertices, \a after) and removes
    all anchors connected to the vertices in \a vertices, returning one simplified anchor between
    \a before and \a after.

    Note that this function doesn't add the created anchor to the graph. This should be done by
    the caller.
*/
static AnchorData *createSequence(Graph<AnchorVertex, AnchorData> *graph, AnchorVertex *before,
                                  const QList<AnchorVertex *> &vertices, AnchorVertex *after)
{
#if defined(QT_DEBUG) && 0
    QString strVertices;
    for (int i = 0; i < vertices.count(); ++i) {
        strVertices += QString::fromLatin1("%1 - ").arg(vertices.at(i)->toString());
    }
    QString strPath = QString::fromLatin1("%1 - %2%3").arg(before->toString(), strVertices, after->toString());
    qDebug("simplifying [%s] to [%s - %s]", qPrintable(strPath), qPrintable(before->toString()), qPrintable(after->toString()));
#endif

    AnchorVertex *prev = before;
    QList<AnchorData *> edges;
    edges.reserve(vertices.count() + 1);

    const int numVertices = vertices.count();
    edges.reserve(numVertices + 1);
    // Take from the graph, the edges that will be simplificated
    for (int i = 0; i < numVertices; ++i) {
        AnchorVertex *next = vertices.at(i);
        AnchorData *ad = graph->takeEdge(prev, next);
        Q_ASSERT(ad);
        edges.append(ad);
        prev = next;
    }

    // Take the last edge (not covered in the loop above)
    AnchorData *ad = graph->takeEdge(vertices.last(), after);
    Q_ASSERT(ad);
    edges.append(ad);

    // Create sequence
    SequentialAnchorData *sequence = new SequentialAnchorData(vertices, edges);
    sequence->from = before;
    sequence->to = after;

    sequence->calculateSizeHints();

    return sequence;
}

/*!
   \internal

   The purpose of this function is to simplify the graph.
   Simplification serves two purposes:
   1. Reduce the number of edges in the graph, (thus the number of variables to the equation
      solver is reduced, and the solver performs better).
   2. Be able to do distribution of sequences of edges more intelligently (esp. with sequential
      anchors)

   It is essential that it must be possible to restore simplified anchors back to their "original"
   form. This is done by restoreSimplifiedAnchor().

   There are two types of simplification that can be done:
   1. Sequential simplification
      Sequential simplification means that all sequences of anchors will be merged into one single
      anchor. Only anhcors that points in the same direction will be merged.
   2. Parallel simplification
      If a simplified sequential anchor is about to be inserted between two vertices in the graph
      and there already exist an anchor between those two vertices, a parallel anchor will be
      created that serves as a placeholder for the sequential anchor and the anchor that was
      already between the two vertices.

   The process of simplification can be described as:

   1. Simplify all sequences of anchors into one anchor.
      If no further simplification was done, go to (3)
      - If there already exist an anchor where the sequential anchor is supposed to be inserted,
        take that anchor out of the graph
      - Then create a parallel anchor that holds the sequential anchor and the anchor just taken
        out of the graph.
   2. Go to (1)
   3. Done

   When creating the parallel anchors, the algorithm might identify unfeasible situations. In this
   case the simplification process stops and returns \c false. Otherwise returns \c true.
*/
bool QGraphicsAnchorLayoutPrivate::simplifyGraph(Qt::Orientation orientation)
{
    if (items.isEmpty())
        return true;

#if defined(QT_DEBUG) && 0
    qDebug("Simplifying Graph for %s",
           orientation == Horizontal ? "Horizontal" : "Vertical");

    static int count = 0;
    if (orientation == Horizontal) {
        count++;
        dumpGraph(QString::fromLatin1("%1-full").arg(count));
    }
#endif

    // Vertex simplification
    if (!simplifyVertices(orientation)) {
        restoreVertices(orientation);
        return false;
    }

    // Anchor simplification
    bool dirty;
    bool feasible = true;
    do {
        dirty = simplifyGraphIteration(orientation, &feasible);
    } while (dirty && feasible);

    // Note that if we are not feasible, we fallback and make sure that the graph is fully restored
    if (!feasible) {
        restoreSimplifiedGraph(orientation);
        restoreVertices(orientation);
        return false;
    }

#if defined(QT_DEBUG) && 0
    dumpGraph(QString::fromLatin1("%1-simplified-%2").arg(count).arg(
                  QString::fromLatin1(orientation == Horizontal ? "Horizontal" : "Vertical")));
#endif

    return true;
}

static AnchorVertex *replaceVertex_helper(AnchorData *data, AnchorVertex *oldV, AnchorVertex *newV)
{
    AnchorVertex *other;
    if (data->from == oldV) {
        data->from = newV;
        other = data->to;
    } else {
        data->to = newV;
        other = data->from;
    }
    return other;
}

bool QGraphicsAnchorLayoutPrivate::replaceVertex(Qt::Orientation orientation, AnchorVertex *oldV,
                                                 AnchorVertex *newV, const QList<AnchorData *> &edges)
{
    Graph<AnchorVertex, AnchorData> &g = graph[orientation];
    bool feasible = true;

    for (int i = 0; i < edges.count(); ++i) {
        AnchorData *ad = edges[i];
        AnchorVertex *otherV = replaceVertex_helper(ad, oldV, newV);

#if defined(QT_DEBUG)
        ad->name = QString::fromLatin1("%1 --to--> %2").arg(ad->from->toString(), ad->to->toString());
#endif

        bool newFeasible;
        AnchorData *newAnchor = addAnchorMaybeParallel(ad, &newFeasible);
        feasible &= newFeasible;

        if (newAnchor != ad) {
            // A parallel was created, we mark that in the list of anchors created by vertex
            // simplification. This is needed because we want to restore them in a separate step
            // from the restoration of anchor simplification.
            anchorsFromSimplifiedVertices[orientation].append(newAnchor);
        }

        g.takeEdge(oldV, otherV);
    }

    return feasible;
}

/*!
    \internal
*/
bool QGraphicsAnchorLayoutPrivate::simplifyVertices(Qt::Orientation orientation)
{
    Q_Q(QGraphicsAnchorLayout);
    Graph<AnchorVertex, AnchorData> &g = graph[orientation];

    // We'll walk through vertices
    QStack<AnchorVertex *> stack;
    stack.push(layoutFirstVertex[orientation]);
    QSet<AnchorVertex *> visited;

    while (!stack.isEmpty()) {
        AnchorVertex *v = stack.pop();
        visited.insert(v);

        // Each adjacent of 'v' is a possible vertex to be merged. So we traverse all of
        // them. Since once a merge is made, we might add new adjacents, and we don't want to
        // pass two times through one adjacent. The 'index' is used to track our position.
        QList<AnchorVertex *> adjacents = g.adjacentVertices(v);
        int index = 0;

        while (index < adjacents.count()) {
            AnchorVertex *next = adjacents.at(index);
            index++;

            AnchorData *data = g.edgeData(v, next);
            const bool bothLayoutVertices = v->m_item == q && next->m_item == q;
            const bool zeroSized = !data->minSize && !data->maxSize;

            if (!bothLayoutVertices && zeroSized) {

                // Create a new vertex pair, note that we keep a list of those vertices so we can
                // easily process them when restoring the graph.
                AnchorVertexPair *newV = new AnchorVertexPair(v, next, data);
                simplifiedVertices[orientation].append(newV);

                // Collect the anchors of both vertices, the new vertex pair will take their place
                // in those anchors
                const QList<AnchorVertex *> &vAdjacents = g.adjacentVertices(v);
                const QList<AnchorVertex *> &nextAdjacents = g.adjacentVertices(next);

                for (int i = 0; i < vAdjacents.count(); ++i) {
                    AnchorVertex *adjacent = vAdjacents.at(i);
                    if (adjacent != next) {
                        AnchorData *ad = g.edgeData(v, adjacent);
                        newV->m_firstAnchors.append(ad);
                    }
                }

                for (int i = 0; i < nextAdjacents.count(); ++i) {
                    AnchorVertex *adjacent = nextAdjacents.at(i);
                    if (adjacent != v) {
                        AnchorData *ad = g.edgeData(next, adjacent);
                        newV->m_secondAnchors.append(ad);

                        // We'll also add new vertices to the adjacent list of the new 'v', to be
                        // created as a vertex pair and replace the current one.
                        if (!adjacents.contains(adjacent))
                            adjacents.append(adjacent);
                    }
                }

                // ### merge this loop into the ones that calculated m_firstAnchors/m_secondAnchors?
                // Make newV take the place of v and next
                bool feasible = replaceVertex(orientation, v, newV, newV->m_firstAnchors);
                feasible &= replaceVertex(orientation, next, newV, newV->m_secondAnchors);

                // Update the layout vertex information if one of the vertices is a layout vertex.
                AnchorVertex *layoutVertex = nullptr;
                if (v->m_item == q)
                    layoutVertex = v;
                else if (next->m_item == q)
                    layoutVertex = next;

                if (layoutVertex) {
                    // Layout vertices always have m_item == q...
                    newV->m_item = q;
                    changeLayoutVertex(orientation, layoutVertex, newV);
                }

                g.takeEdge(v, next);

                // If a non-feasibility is found, we leave early and cancel the simplification
                if (!feasible)
                    return false;

                v = newV;
                visited.insert(newV);

            } else if (!visited.contains(next) && !stack.contains(next)) {
                // If the adjacent is not fit for merge and it wasn't visited by the outermost
                // loop, we add it to the stack.
                stack.push(next);
            }
        }
    }

    return true;
}

/*!
    \internal

    One iteration of the simplification algorithm. Returns \c true if another iteration is needed.

    The algorithm walks the graph in depth-first order, and only collects vertices that has two
    edges connected to it.  If the vertex does not have two edges or if it is a layout edge, it
    will take all the previously collected vertices and try to create a simplified sequential
    anchor representing all the previously collected vertices.  Once the simplified anchor is
    inserted, the collected list is cleared in order to find the next sequence to simplify.

    Note that there are some catches to this that are not covered by the above explanation, see
    the function comments for more details.
*/
bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(Qt::Orientation orientation,
                                                          bool *feasible)
{
    Q_Q(QGraphicsAnchorLayout);
    Graph<AnchorVertex, AnchorData> &g = graph[orientation];

    QSet<AnchorVertex *> visited;
    QStack<QPair<AnchorVertex *, AnchorVertex *> > stack;
    stack.push(qMakePair(static_cast<AnchorVertex *>(nullptr), layoutFirstVertex[orientation]));
    QList<AnchorVertex *> candidates;

    // Walk depth-first, in the stack we store start of the candidate sequence (beforeSequence)
    // and the vertex to be visited.
    while (!stack.isEmpty()) {
        QPair<AnchorVertex *, AnchorVertex *> pair = stack.pop();
        AnchorVertex *beforeSequence = pair.first;
        AnchorVertex *v = pair.second;

        // The basic idea is to determine whether we found an end of sequence,
        // if that's the case, we stop adding vertices to the candidate list
        // and do a simplification step.
        //
        // A vertex can trigger an end of sequence if
        // (a) it is a layout vertex, we don't simplify away the layout vertices;
        // (b) it does not have exactly 2 adjacents;
        // (c) its next adjacent is already visited (a cycle in the graph).
        // (d) the next anchor is a center anchor.

        const QList<AnchorVertex *> &adjacents = g.adjacentVertices(v);
        const bool isLayoutVertex = v->m_item == q;
        AnchorVertex *afterSequence = v;
        bool endOfSequence = false;

        //
        // Identify the end cases.
        //

        // Identifies cases (a) and (b)
        endOfSequence = isLayoutVertex || adjacents.count() != 2;

        if (!endOfSequence) {
            // This is a tricky part. We peek at the next vertex to find out whether
            //
            // - we already visited the next vertex (c);
            // - the next anchor is a center (d).
            //
            // Those are needed to identify the remaining end of sequence cases. Note that unlike
            // (a) and (b), we preempt the end of sequence by looking into the next vertex.

            // Peek at the next vertex
            AnchorVertex *after;
            if (candidates.isEmpty())
                after = (beforeSequence == adjacents.last() ? adjacents.first() : adjacents.last());
            else
                after = (candidates.constLast() == adjacents.last() ? adjacents.first() : adjacents.last());

            // ### At this point we assumed that candidates will not contain 'after', this may not hold
            // when simplifying FLOATing anchors.
            Q_ASSERT(!candidates.contains(after));

            const AnchorData *data = g.edgeData(v, after);
            Q_ASSERT(data);
            const bool cycleFound = visited.contains(after);

            // Now cases (c) and (d)...
            endOfSequence = cycleFound || data->isCenterAnchor;

            if (!endOfSequence) {
                // If it's not an end of sequence, then the vertex didn't trigger neither of the
                // previously three cases, so it can be added to the candidates list.
                candidates.append(v);
            } else if (cycleFound && (beforeSequence != after)) {
                afterSequence = after;
                candidates.append(v);
            }
        }

        //
        // Add next non-visited vertices to the stack.
        //
        for (int i = 0; i < adjacents.count(); ++i) {
            AnchorVertex *next = adjacents.at(i);
            if (visited.contains(next))
                continue;

            // If current vertex is an end of sequence, and it'll reset the candidates list. So
            // the next vertices will build candidates lists with the current vertex as 'before'
            // vertex. If it's not an end of sequence, we keep the original 'before' vertex,
            // since we are keeping the candidates list.
            if (endOfSequence)
                stack.push(qMakePair(v, next));
            else
                stack.push(qMakePair(beforeSequence, next));
        }

        visited.insert(v);

        if (!endOfSequence || candidates.isEmpty())
            continue;

        //
        // Create a sequence for (beforeSequence, candidates, afterSequence).
        //

        // One restriction we have is to not simplify half of an anchor and let the other half
        // unsimplified. So we remove center edges before and after the sequence.
        const AnchorData *firstAnchor = g.edgeData(beforeSequence, candidates.constFirst());
        if (firstAnchor->isCenterAnchor) {
            beforeSequence = candidates.constFirst();
            candidates.remove(0);

            // If there's not candidates to be simplified, leave.
            if (candidates.isEmpty())
                continue;
        }

        const AnchorData *lastAnchor = g.edgeData(candidates.constLast(), afterSequence);
        if (lastAnchor->isCenterAnchor) {
            afterSequence = candidates.constLast();
            candidates.remove(candidates.count() - 1);

            if (candidates.isEmpty())
                continue;
        }

        //
        // Add the sequence to the graph.
        //

        AnchorData *sequence = createSequence(&g, beforeSequence, candidates, afterSequence);

        // If 'beforeSequence' and 'afterSequence' already had an anchor between them, we'll
        // create a parallel anchor between the new sequence and the old anchor.
        bool newFeasible;
        AnchorData *newAnchor = addAnchorMaybeParallel(sequence, &newFeasible);

        if (!newFeasible) {
            *feasible = false;
            return false;
        }

        // When a new parallel anchor is create in the graph, we finish the iteration and return
        // true to indicate a new iteration is needed. This happens because a parallel anchor
        // changes the number of adjacents one vertex has, possibly opening up oportunities for
        // building candidate lists (when adjacents == 2).
        if (newAnchor != sequence)
            return true;

        // If there was no parallel simplification, we'll keep walking the graph. So we clear the
        // candidates list to start again.
        candidates.clear();
    }

    return false;
}

void QGraphicsAnchorLayoutPrivate::restoreSimplifiedAnchor(AnchorData *edge)
{
    const Qt::Orientation orientation = edge->isVertical ? Qt::Vertical : Qt::Horizontal;
#if 0
    static const char *anchortypes[] = {"Normal",
                                        "Sequential",
                                        "Parallel"};
    qDebug("Restoring %s edge.", anchortypes[int(edge->type)]);
#endif

    Graph<AnchorVertex, AnchorData> &g = graph[orientation];

    if (edge->type == AnchorData::Normal) {
        g.createEdge(edge->from, edge->to, edge);

    } else if (edge->type == AnchorData::Sequential) {
        SequentialAnchorData *sequence = static_cast<SequentialAnchorData *>(edge);

        for (int i = 0; i < sequence->m_edges.count(); ++i) {
            AnchorData *data = sequence->m_edges.at(i);
            restoreSimplifiedAnchor(data);
        }

        delete sequence;

    } else if (edge->type == AnchorData::Parallel) {

        // Skip parallel anchors that were created by vertex simplification, they will be processed
        // later, when restoring vertex simplification.
        // ### we could improve this check bit having a bit inside 'edge'
        if (anchorsFromSimplifiedVertices[orientation].contains(edge))
            return;

        ParallelAnchorData* parallel = static_cast<ParallelAnchorData*>(edge);
        restoreSimplifiedConstraints(parallel);

        // ### Because of the way parallel anchors are created in the anchor simplification
        // algorithm, we know that one of these will be a sequence, so it'll be safe if the other
        // anchor create an edge between the same vertices as the parallel.
        Q_ASSERT(parallel->firstEdge->type == AnchorData::Sequential
                 || parallel->secondEdge->type == AnchorData::Sequential);
        restoreSimplifiedAnchor(parallel->firstEdge);
        restoreSimplifiedAnchor(parallel->secondEdge);

        delete parallel;
    }
}

void QGraphicsAnchorLayoutPrivate::restoreSimplifiedConstraints(ParallelAnchorData *parallel)
{
    if (!parallel->isCenterAnchor)
        return;

    for (int i = 0; i < parallel->m_firstConstraints.count(); ++i) {
        QSimplexConstraint *c = parallel->m_firstConstraints.at(i);
        qreal v = c->variables[parallel];
        c->variables.remove(parallel);
        c->variables.insert(parallel->firstEdge, v);
    }

    // When restoring, we might have to revert constraints back. See comments on
    // addAnchorMaybeParallel().
    const bool needsReverse = !parallel->secondForward();

    for (int i = 0; i < parallel->m_secondConstraints.count(); ++i) {
        QSimplexConstraint *c = parallel->m_secondConstraints.at(i);
        qreal v = c->variables[parallel];
        if (needsReverse)
            v *= -1;
        c->variables.remove(parallel);
        c->variables.insert(parallel->secondEdge, v);
    }
}

void QGraphicsAnchorLayoutPrivate::restoreSimplifiedGraph(Qt::Orientation orientation)
{
#if 0
    qDebug("Restoring Simplified Graph for %s",
           orientation == Horizontal ? "Horizontal" : "Vertical");
#endif

    // Restore anchor simplification
    Graph<AnchorVertex, AnchorData> &g = graph[orientation];
    QList<QPair<AnchorVertex *, AnchorVertex *>> connections = g.connections();
    for (int i = 0; i < connections.count(); ++i) {
        AnchorVertex *v1 = connections.at(i).first;
        AnchorVertex *v2 = connections.at(i).second;
        AnchorData *edge = g.edgeData(v1, v2);

        // We restore only sequential anchors and parallels that were not created by
        // vertex simplification.
        if (edge->type == AnchorData::Sequential
            || (edge->type == AnchorData::Parallel &&
                !anchorsFromSimplifiedVertices[orientation].contains(edge))) {

            g.takeEdge(v1, v2);
            restoreSimplifiedAnchor(edge);
        }
    }

    restoreVertices(orientation);
}

void QGraphicsAnchorLayoutPrivate::restoreVertices(Qt::Orientation orientation)
{
    Q_Q(QGraphicsAnchorLayout);

    Graph<AnchorVertex, AnchorData> &g = graph[orientation];
    QList<AnchorVertexPair *> &toRestore = simplifiedVertices[orientation];

    // Since we keep a list of parallel anchors and vertices that were created during vertex
    // simplification, we can now iterate on those lists instead of traversing the graph
    // recursively.

    // First, restore the constraints changed when we created parallel anchors. Note that this
    // works at this point because the constraints doesn't depend on vertex information and at
    // this point it's always safe to identify whether the second child is forward or backwards.
    // In the next step, we'll change the anchors vertices so that would not be possible anymore.
    QList<AnchorData *> &parallelAnchors = anchorsFromSimplifiedVertices[orientation];

    for (int i = parallelAnchors.count() - 1; i >= 0; --i) {
        ParallelAnchorData *parallel = static_cast<ParallelAnchorData *>(parallelAnchors.at(i));
        restoreSimplifiedConstraints(parallel);
    }

    // Then, we will restore the vertices in the inverse order of creation, this way we ensure that
    // the vertex being restored was not wrapped by another simplification.
    for (int i = toRestore.count() - 1; i >= 0; --i) {
        AnchorVertexPair *pair = toRestore.at(i);
        QList<AnchorVertex *> adjacents = g.adjacentVertices(pair);

        // Restore the removed edge, this will also restore both vertices 'first' and 'second' to
        // the graph structure.
        AnchorVertex *first = pair->m_first;
        AnchorVertex *second = pair->m_second;
        g.createEdge(first, second, pair->m_removedAnchor);

        // Restore the anchors for the first child vertex
        for (int j = 0; j < pair->m_firstAnchors.count(); ++j) {
            AnchorData *ad = pair->m_firstAnchors.at(j);
            Q_ASSERT(ad->from == pair || ad->to == pair);

            replaceVertex_helper(ad, pair, first);
            g.createEdge(ad->from, ad->to, ad);
        }

        // Restore the anchors for the second child vertex
        for (int j = 0; j < pair->m_secondAnchors.count(); ++j) {
            AnchorData *ad = pair->m_secondAnchors.at(j);
            Q_ASSERT(ad->from == pair || ad->to == pair);

            replaceVertex_helper(ad, pair, second);
            g.createEdge(ad->from, ad->to, ad);
        }

        for (int j = 0; j < adjacents.count(); ++j) {
            g.takeEdge(pair, adjacents.at(j));
        }

        // The pair simplified a layout vertex, so place back the correct vertex in the variable
        // that track layout vertices
        if (pair->m_item == q) {
            AnchorVertex *layoutVertex = first->m_item == q ? first : second;
            Q_ASSERT(layoutVertex->m_item == q);
            changeLayoutVertex(orientation, pair, layoutVertex);
        }

        delete pair;
    }
    qDeleteAll(parallelAnchors);
    parallelAnchors.clear();
    toRestore.clear();
}

Qt::Orientation
QGraphicsAnchorLayoutPrivate::edgeOrientation(Qt::AnchorPoint edge) noexcept
{
    return edge > Qt::AnchorRight ? Qt::Vertical : Qt::Horizontal;
}

/*!
  \internal

  Create internal anchors to connect the layout edges (Left to Right and
  Top to Bottom).

  These anchors doesn't have size restrictions, that will be enforced by
  other anchors and items in the layout.
*/
void QGraphicsAnchorLayoutPrivate::createLayoutEdges()
{
    Q_Q(QGraphicsAnchorLayout);
    QGraphicsLayoutItem *layout = q;

    // Horizontal
    AnchorData *data = new AnchorData;
    addAnchor_helper(layout, Qt::AnchorLeft, layout,
                     Qt::AnchorRight, data);
    data->maxSize = QWIDGETSIZE_MAX;

    // Save a reference to layout vertices
    layoutFirstVertex[Qt::Horizontal] = internalVertex(layout, Qt::AnchorLeft);
    layoutCentralVertex[Qt::Horizontal] = nullptr;
    layoutLastVertex[Qt::Horizontal] = internalVertex(layout, Qt::AnchorRight);

    // Vertical
    data = new AnchorData;
    addAnchor_helper(layout, Qt::AnchorTop, layout,
                     Qt::AnchorBottom, data);
    data->maxSize = QWIDGETSIZE_MAX;

    // Save a reference to layout vertices
    layoutFirstVertex[Qt::Vertical] = internalVertex(layout, Qt::AnchorTop);
    layoutCentralVertex[Qt::Vertical] = nullptr;
    layoutLastVertex[Qt::Vertical] = internalVertex(layout, Qt::AnchorBottom);
}

void QGraphicsAnchorLayoutPrivate::deleteLayoutEdges()
{
    Q_Q(QGraphicsAnchorLayout);

    Q_ASSERT(!internalVertex(q, Qt::AnchorHorizontalCenter));
    Q_ASSERT(!internalVertex(q, Qt::AnchorVerticalCenter));

    removeAnchor_helper(internalVertex(q, Qt::AnchorLeft),
                        internalVertex(q, Qt::AnchorRight));
    removeAnchor_helper(internalVertex(q, Qt::AnchorTop),
                        internalVertex(q, Qt::AnchorBottom));
}

void QGraphicsAnchorLayoutPrivate::createItemEdges(QGraphicsLayoutItem *item)
{
    items.append(item);

    // Create horizontal and vertical internal anchors for the item and
    // refresh its size hint / policy values.
    AnchorData *data = new AnchorData;
    addAnchor_helper(item, Qt::AnchorLeft, item, Qt::AnchorRight, data);
    data->refreshSizeHints();

    data = new AnchorData;
    addAnchor_helper(item, Qt::AnchorTop, item, Qt::AnchorBottom, data);
    data->refreshSizeHints();
}

/*!
  \internal

  By default, each item in the layout is represented internally as
  a single anchor in each direction. For instance, from Left to Right.

  However, to support anchorage of items to the center of items, we
  must split this internal anchor into two half-anchors. From Left
  to Center and then from Center to Right, with the restriction that
  these anchors must have the same time at all times.
*/
void QGraphicsAnchorLayoutPrivate::createCenterAnchors(
    QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge)
{
    Q_Q(QGraphicsAnchorLayout);

    Qt::Orientation orientation;
    switch (centerEdge) {
    case Qt::AnchorHorizontalCenter:
        orientation = Qt::Horizontal;
        break;
    case Qt::AnchorVerticalCenter:
        orientation = Qt::Vertical;
        break;
    default:
        // Don't create center edges unless needed
        return;
    }

    // Check if vertex already exists
    if (internalVertex(item, centerEdge))
        return;

    // Orientation code
    Qt::AnchorPoint firstEdge;
    Qt::AnchorPoint lastEdge;

    if (orientation == Qt::Horizontal) {
        firstEdge = Qt::AnchorLeft;
        lastEdge = Qt::AnchorRight;
    } else {
        firstEdge = Qt::AnchorTop;
        lastEdge = Qt::AnchorBottom;
    }

    AnchorVertex *first = internalVertex(item, firstEdge);
    AnchorVertex *last = internalVertex(item, lastEdge);
    Q_ASSERT(first && last);

    // Create new anchors
    QSimplexConstraint *c = new QSimplexConstraint;

    AnchorData *data = new AnchorData;
    c->variables.insert(data, 1.0);
    addAnchor_helper(item, firstEdge, item, centerEdge, data);
    data->isCenterAnchor = true;
    data->dependency = AnchorData::Master;
    data->refreshSizeHints();

    data = new AnchorData;
    c->variables.insert(data, -1.0);
    addAnchor_helper(item, centerEdge, item, lastEdge, data);
    data->isCenterAnchor = true;
    data->dependency = AnchorData::Slave;
    data->refreshSizeHints();

    itemCenterConstraints[orientation].append(c);

    // Remove old one
    removeAnchor_helper(first, last);

    if (item == q) {
        layoutCentralVertex[orientation] = internalVertex(q, centerEdge);
    }
}

void QGraphicsAnchorLayoutPrivate::removeCenterAnchors(
    QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge,
    bool substitute)
{
    Q_Q(QGraphicsAnchorLayout);

    Qt::Orientation orientation;
    switch (centerEdge) {
    case Qt::AnchorHorizontalCenter:
        orientation = Qt::Horizontal;
        break;
    case Qt::AnchorVerticalCenter:
        orientation = Qt::Vertical;
        break;
    default:
        // Don't remove edges that not the center ones
        return;
    }

    // Orientation code
    Qt::AnchorPoint firstEdge;
    Qt::AnchorPoint lastEdge;

    if (orientation == Qt::Horizontal) {
        firstEdge = Qt::AnchorLeft;
        lastEdge = Qt::AnchorRight;
    } else {
        firstEdge = Qt::AnchorTop;
        lastEdge = Qt::AnchorBottom;
    }

    AnchorVertex *center = internalVertex(item, centerEdge);
    if (!center)
        return;
    AnchorVertex *first = internalVertex(item, firstEdge);

    Q_ASSERT(first);
    Q_ASSERT(center);

    Graph<AnchorVertex, AnchorData> &g = graph[orientation];


    AnchorData *oldData = g.edgeData(first, center);
    // Remove center constraint
    for (int i = itemCenterConstraints[orientation].count() - 1; i >= 0; --i) {
        if (itemCenterConstraints[orientation].at(i)->variables.contains(oldData)) {
            delete itemCenterConstraints[orientation].takeAt(i);
            break;
        }
    }

    if (substitute) {
        // Create the new anchor that should substitute the left-center-right anchors.
        AnchorData *data = new AnchorData;
        addAnchor_helper(item, firstEdge, item, lastEdge, data);
        data->refreshSizeHints();

        // Remove old anchors
        removeAnchor_helper(first, center);
        removeAnchor_helper(center, internalVertex(item, lastEdge));

    } else {
        // this is only called from removeAnchors()
        // first, remove all non-internal anchors
        QList<AnchorVertex*> adjacents = g.adjacentVertices(center);
        for (int i = 0; i < adjacents.count(); ++i) {
            AnchorVertex *v = adjacents.at(i);
            if (v->m_item != item) {
                removeAnchor_helper(center, internalVertex(v->m_item, v->m_edge));
            }
        }
        // when all non-internal anchors is removed it will automatically merge the
        // center anchor into a left-right (or top-bottom) anchor. We must also delete that.
        // by this time, the center vertex is deleted and merged into a non-centered internal anchor
        removeAnchor_helper(first, internalVertex(item, lastEdge));
    }

    if (item == q) {
        layoutCentralVertex[orientation] = nullptr;
    }
}


void QGraphicsAnchorLayoutPrivate::removeCenterConstraints(QGraphicsLayoutItem *item,
                                                           Qt::Orientation orientation)
{
    // Remove the item center constraints associated to this item
    // ### This is a temporary solution. We should probably use a better
    // data structure to hold items and/or their associated constraints
    // so that we can remove those easily

    AnchorVertex *first = internalVertex(item, orientation == Qt::Horizontal ?
                                       Qt::AnchorLeft :
                                       Qt::AnchorTop);
    AnchorVertex *center = internalVertex(item, orientation == Qt::Horizontal ?
                                        Qt::AnchorHorizontalCenter :
                                        Qt::AnchorVerticalCenter);

    // Skip if no center constraints exist
    if (!center)
        return;

    Q_ASSERT(first);
    AnchorData *internalAnchor = graph[orientation].edgeData(first, center);

    // Look for our anchor in all item center constraints, then remove it
    for (int i = 0; i < itemCenterConstraints[orientation].size(); ++i) {
        if (itemCenterConstraints[orientation].at(i)->variables.contains(internalAnchor)) {
            delete itemCenterConstraints[orientation].takeAt(i);
            break;
        }
    }
}

/*!
 * \internal
 * Implements the high level "addAnchor" feature. Called by the public API
 * addAnchor method.
 *
 * The optional \a spacing argument defines the size of the anchor. If not provided,
 * the anchor size is either 0 or not-set, depending on type of anchor created (see
 * matrix below).
 *
 * All anchors that remain with size not-set will assume the standard spacing,
 * set either by the layout style or through the "setSpacing" layout API.
 */
QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *firstItem,
                                                         Qt::AnchorPoint firstEdge,
                                                         QGraphicsLayoutItem *secondItem,
                                                         Qt::AnchorPoint secondEdge,
                                                         qreal *spacing)
{
    Q_Q(QGraphicsAnchorLayout);
    if ((firstItem == nullptr) || (secondItem == nullptr)) {
        qWarning("QGraphicsAnchorLayout::addAnchor(): "
                 "Cannot anchor NULL items");
        return nullptr;
    }

    if (firstItem == secondItem) {
        qWarning("QGraphicsAnchorLayout::addAnchor(): "
                 "Cannot anchor the item to itself");
        return nullptr;
    }

    if (edgeOrientation(secondEdge) != edgeOrientation(firstEdge)) {
        qWarning("QGraphicsAnchorLayout::addAnchor(): "
                 "Cannot anchor edges of different orientations");
        return nullptr;
    }

    const QGraphicsLayoutItem *parentWidget = q->parentLayoutItem();
    if (firstItem == parentWidget || secondItem == parentWidget) {
        qWarning("QGraphicsAnchorLayout::addAnchor(): "
                 "You cannot add the parent of the layout to the layout.");
        return nullptr;
    }

    // In QGraphicsAnchorLayout, items are represented in its internal
    // graph as four anchors that connect:
    //  - Left -> HCenter
    //  - HCenter-> Right
    //  - Top -> VCenter
    //  - VCenter -> Bottom

    // Ensure that the internal anchors have been created for both items.
    if (firstItem != q && !items.contains(firstItem)) {
        createItemEdges(firstItem);
        addChildLayoutItem(firstItem);
    }
    if (secondItem != q && !items.contains(secondItem)) {
        createItemEdges(secondItem);
        addChildLayoutItem(secondItem);
    }

    // Create center edges if needed
    createCenterAnchors(firstItem, firstEdge);
    createCenterAnchors(secondItem, secondEdge);

    // Use heuristics to find out what the user meant with this anchor.
    correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge);

    AnchorData *data = new AnchorData;
    QGraphicsAnchor *graphicsAnchor = acquireGraphicsAnchor(data);

    addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data);

    if (spacing) {
        graphicsAnchor->setSpacing(*spacing);
    } else {
        // If firstItem or secondItem is the layout itself, the spacing will default to 0.
        // Otherwise, the following matrix is used (questionmark means that the spacing
        // is queried from the style):
        //                from
        //  to      Left    HCenter Right
        //  Left    0       0       ?
        //  HCenter 0       0       0
        //  Right   ?       0       0
        if (firstItem == q
            || secondItem == q
            || pickEdge(firstEdge, Qt::Horizontal) == Qt::AnchorHorizontalCenter
            || oppositeEdge(firstEdge) != secondEdge) {
            graphicsAnchor->setSpacing(0);
        } else {
            graphicsAnchor->unsetSpacing();
        }
    }

    return graphicsAnchor;
}

/*
  \internal

  This method adds an AnchorData to the internal graph. It is responsible for doing
  the boilerplate part of such task.

  If another AnchorData exists between the mentioned vertices, it is deleted and
  the new one is inserted.
*/
void QGraphicsAnchorLayoutPrivate::addAnchor_helper(QGraphicsLayoutItem *firstItem,
                                                    Qt::AnchorPoint firstEdge,
                                                    QGraphicsLayoutItem *secondItem,
                                                    Qt::AnchorPoint secondEdge,
                                                    AnchorData *data)
{
    Q_Q(QGraphicsAnchorLayout);

    const Qt::Orientation orientation = edgeOrientation(firstEdge);

    // Create or increase the reference count for the related vertices.
    AnchorVertex *v1 = addInternalVertex(firstItem, firstEdge);
    AnchorVertex *v2 = addInternalVertex(secondItem, secondEdge);

    // Remove previous anchor
    if (graph[orientation].edgeData(v1, v2)) {
        removeAnchor_helper(v1, v2);
    }

    // If its an internal anchor, set the associated item
    if (firstItem == secondItem)
        data->item = firstItem;

    data->isVertical = orientation == Qt::Vertical;

    // Create a bi-directional edge in the sense it can be transversed both
    // from v1 or v2. "data" however is shared between the two references
    // so we still know that the anchor direction is from 1 to 2.
    data->from = v1;
    data->to = v2;
#ifdef QT_DEBUG
    data->name = QString::fromLatin1("%1 --to--> %2").arg(v1->toString(), v2->toString());
#endif
    // ### bit to track internal anchors, since inside AnchorData methods
    // we don't have access to the 'q' pointer.
    data->isLayoutAnchor = (data->item == q);

    graph[orientation].createEdge(v1, v2, data);
}

QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::getAnchor(QGraphicsLayoutItem *firstItem,
                                                         Qt::AnchorPoint firstEdge,
                                                         QGraphicsLayoutItem *secondItem,
                                                         Qt::AnchorPoint secondEdge)
{
    // Do not expose internal anchors
    if (firstItem == secondItem)
        return nullptr;

    const Qt::Orientation orientation = edgeOrientation(firstEdge);
    AnchorVertex *v1 = internalVertex(firstItem, firstEdge);
    AnchorVertex *v2 = internalVertex(secondItem, secondEdge);

    QGraphicsAnchor *graphicsAnchor = nullptr;

    AnchorData *data = graph[orientation].edgeData(v1, v2);
    if (data) {
        // We could use "acquireGraphicsAnchor" here, but to avoid a regression where
        // an internal anchor was wrongly exposed, I want to ensure no new
        // QGraphicsAnchor instances are created by this call.
        // This assumption must hold because anchors are either user-created (and already
        // have their public object created), or they are internal (and must not reach
        // this point).
        Q_ASSERT(data->graphicsAnchor);
        graphicsAnchor = data->graphicsAnchor;
    }
    return graphicsAnchor;
}

/*!
 * \internal
 *
 * Implements the high level "removeAnchor" feature. Called by
 * the QAnchorData destructor.
 */
void QGraphicsAnchorLayoutPrivate::removeAnchor(AnchorVertex *firstVertex,
                                                AnchorVertex *secondVertex)
{
    Q_Q(QGraphicsAnchorLayout);

    // Save references to items while it's safe to assume the vertices exist
    QGraphicsLayoutItem *firstItem = firstVertex->m_item;
    QGraphicsLayoutItem *secondItem = secondVertex->m_item;

    // Delete the anchor (may trigger deletion of center vertices)
    removeAnchor_helper(firstVertex, secondVertex);

    // Ensure no dangling pointer is left behind
    firstVertex = secondVertex = nullptr;

    // Checking if the item stays in the layout or not
    bool keepFirstItem = false;
    bool keepSecondItem = false;

    QPair<AnchorVertex *, int> v;
    int refcount = -1;

    if (firstItem != q) {
        for (int i = Qt::AnchorLeft; i <= Qt::AnchorBottom; ++i) {
            v = m_vertexList.value(qMakePair(firstItem, static_cast<Qt::AnchorPoint>(i)));
            if (v.first) {
                if (i == Qt::AnchorHorizontalCenter || i == Qt::AnchorVerticalCenter)
                    refcount = 2;
                else
                    refcount = 1;

                if (v.second > refcount) {
                    keepFirstItem = true;
                    break;
                }
            }
        }
    } else
        keepFirstItem = true;

    if (secondItem != q) {
        for (int i = Qt::AnchorLeft; i <= Qt::AnchorBottom; ++i) {
            v = m_vertexList.value(qMakePair(secondItem, static_cast<Qt::AnchorPoint>(i)));
            if (v.first) {
                if (i == Qt::AnchorHorizontalCenter || i == Qt::AnchorVerticalCenter)
                    refcount = 2;
                else
                    refcount = 1;

                if (v.second > refcount) {
                    keepSecondItem = true;
                    break;
                }
            }
        }
    } else
        keepSecondItem = true;

    if (!keepFirstItem)
        q->removeAt(items.indexOf(firstItem));

    if (!keepSecondItem)
        q->removeAt(items.indexOf(secondItem));

    // Removing anchors invalidates the layout
    q->invalidate();
}

/*
  \internal

  Implements the low level "removeAnchor" feature. Called by
  private methods.
*/
void QGraphicsAnchorLayoutPrivate::removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2)
{
    Q_ASSERT(v1 && v2);

    // Remove edge from graph
    const Qt::Orientation o = edgeOrientation(v1->m_edge);
    graph[o].removeEdge(v1, v2);

    // Decrease vertices reference count (may trigger a deletion)
    removeInternalVertex(v1->m_item, v1->m_edge);
    removeInternalVertex(v2->m_item, v2->m_edge);
}

AnchorVertex *QGraphicsAnchorLayoutPrivate::addInternalVertex(QGraphicsLayoutItem *item,
                                                              Qt::AnchorPoint edge)
{
    QPair<QGraphicsLayoutItem *, Qt::AnchorPoint> pair(item, edge);
    QPair<AnchorVertex *, int> v = m_vertexList.value(pair);

    if (!v.first) {
        Q_ASSERT(v.second == 0);
        v.first = new AnchorVertex(item, edge);
    }
    v.second++;
    m_vertexList.insert(pair, v);
    return v.first;
}

/**
 * \internal
 *
 * returns the AnchorVertex that was dereferenced, also when it was removed.
 * returns 0 if it did not exist.
 */
void QGraphicsAnchorLayoutPrivate::removeInternalVertex(QGraphicsLayoutItem *item,
                                                        Qt::AnchorPoint edge)
{
    QPair<QGraphicsLayoutItem *, Qt::AnchorPoint> pair(item, edge);
    QPair<AnchorVertex *, int> v = m_vertexList.value(pair);

    if (!v.first) {
        qWarning("This item with this edge is not in the graph");
        return;
    }

    v.second--;
    if (v.second == 0) {
        // Remove reference and delete vertex
        m_vertexList.remove(pair);
        delete v.first;
    } else {
        // Update reference count
        m_vertexList.insert(pair, v);

        if ((v.second == 2) &&
            ((edge == Qt::AnchorHorizontalCenter) ||
             (edge == Qt::AnchorVerticalCenter))) {
            removeCenterAnchors(item, edge, true);
        }
    }
}

void QGraphicsAnchorLayoutPrivate::removeVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge)
{
    if (AnchorVertex *v = internalVertex(item, edge)) {
        Graph<AnchorVertex, AnchorData> &g = graph[edgeOrientation(edge)];
        const auto allVertices = g.adjacentVertices(v);
        for (auto *v2 : allVertices) {
            g.removeEdge(v, v2);
            removeInternalVertex(item, edge);
            removeInternalVertex(v2->m_item, v2->m_edge);
        }
    }
}

void QGraphicsAnchorLayoutPrivate::removeAnchors(QGraphicsLayoutItem *item)
{
    // remove the center anchor first!!
    removeCenterAnchors(item, Qt::AnchorHorizontalCenter, false);
    removeVertex(item, Qt::AnchorLeft);
    removeVertex(item, Qt::AnchorRight);

    removeCenterAnchors(item, Qt::AnchorVerticalCenter, false);
    removeVertex(item, Qt::AnchorTop);
    removeVertex(item, Qt::AnchorBottom);
}

/*!
  \internal

  Use heuristics to determine the correct orientation of a given anchor.

  After API discussions, we decided we would like expressions like
  anchor(A, Left, B, Right) to mean the same as anchor(B, Right, A, Left).
  The problem with this is that anchors could become ambiguous, for
  instance, what does the anchor A, B of size X mean?

     "pos(B) = pos(A) + X"  or  "pos(A) = pos(B) + X" ?

  To keep the API user friendly and at the same time, keep our algorithm
  deterministic, we use an heuristic to determine a direction for each
  added anchor and then keep it. The heuristic is based on the fact
  that people usually avoid overlapping items, therefore:

     "A, RIGHT to B, LEFT" means that B is to the LEFT of A.
     "B, LEFT to A, RIGHT" is corrected to the above anchor.

  Special correction is also applied when one of the items is the
  layout. We handle Layout Left as if it was another items's Right
  and Layout Right as another item's Left.
*/
void QGraphicsAnchorLayoutPrivate::correctEdgeDirection(QGraphicsLayoutItem *&firstItem,
                                                        Qt::AnchorPoint &firstEdge,
                                                        QGraphicsLayoutItem *&secondItem,
                                                        Qt::AnchorPoint &secondEdge)
{
    Q_Q(QGraphicsAnchorLayout);

    if ((firstItem != q) && (secondItem != q)) {
        // If connection is between widgets (not the layout itself)
        // Ensure that "right-edges" sit to the left of "left-edges".
        if (firstEdge < secondEdge) {
            qSwap(firstItem, secondItem);
            qSwap(firstEdge, secondEdge);
        }
    } else if (firstItem == q) {
        // If connection involves the right or bottom of a layout, ensure
        // the layout is the second item.
        if ((firstEdge == Qt::AnchorRight) || (firstEdge == Qt::AnchorBottom)) {
            qSwap(firstItem, secondItem);
            qSwap(firstEdge, secondEdge);
        }
    } else if ((secondEdge != Qt::AnchorRight) && (secondEdge != Qt::AnchorBottom)) {
        // If connection involves the left, center or top of layout, ensure
        // the layout is the first item.
        qSwap(firstItem, secondItem);
        qSwap(firstEdge, secondEdge);
    }
}

QLayoutStyleInfo &QGraphicsAnchorLayoutPrivate::styleInfo() const
{
    if (styleInfoDirty) {
        Q_Q(const QGraphicsAnchorLayout);
        //### Fix this if QGV ever gets support for Metal style or different Aqua sizes.
        QWidget *wid = nullptr;

        QGraphicsLayoutItem *parent = q->parentLayoutItem();
        while (parent && parent->isLayout()) {
            parent = parent->parentLayoutItem();
        }
        QGraphicsWidget *w = nullptr;
        if (parent) {
            QGraphicsItem *parentItem = parent->graphicsItem();
            if (parentItem && parentItem->isWidget())
                w = static_cast<QGraphicsWidget*>(parentItem);
        }

        QStyle *style = w ? w->style() : QApplication::style();
        cachedStyleInfo = QLayoutStyleInfo(style, wid);
        cachedStyleInfo.setDefaultSpacing(Qt::Horizontal, spacings[Qt::Horizontal]);
        cachedStyleInfo.setDefaultSpacing(Qt::Vertical, spacings[Qt::Vertical]);

        styleInfoDirty = false;
    }
    return cachedStyleInfo;
}

/*!
  \internal

  Called on activation. Uses Linear Programming to define minimum, preferred
  and maximum sizes for the layout. Also calculates the sizes that each item
  should assume when the layout is in one of such situations.
*/
void QGraphicsAnchorLayoutPrivate::calculateGraphs()
{
    if (!calculateGraphCacheDirty)
        return;
    calculateGraphs(Qt::Horizontal);
    calculateGraphs(Qt::Vertical);
    calculateGraphCacheDirty = false;
}

// ### Maybe getGraphParts could return the variables when traversing, at least
// for trunk...
QList<AnchorData *> getVariables(const QList<QSimplexConstraint *> &constraints)
{
    QSet<AnchorData *> variableSet;
    for (int i = 0; i < constraints.count(); ++i) {
        const QSimplexConstraint *c = constraints.at(i);
        for (auto it = c->variables.cbegin(), end = c->variables.cend(); it != end; ++it)
            variableSet.insert(static_cast<AnchorData *>(it.key()));
    }
    return variableSet.values();
}

/*!
    \internal

    Calculate graphs is the method that puts together all the helper routines
    so that the AnchorLayout can calculate the sizes of each item.

    In a nutshell it should do:

    1) Refresh anchor nominal sizes, that is, the size that each anchor would
       have if no other restrictions applied. This is done by querying the
       layout style and the sizeHints of the items belonging to the layout.

    2) Simplify the graph by grouping together parallel and sequential anchors
       into "group anchors". These have equivalent minimum, preferred and maximum
       sizeHints as the anchors they replace.

    3) Check if we got to a trivial case. In some cases, the whole graph can be
       simplified into a single anchor. If so, use this information. If not,
       then call the Simplex solver to calculate the anchors sizes.

    4) Once the root anchors had its sizes calculated, propagate that to the
       anchors they represent.
*/
void QGraphicsAnchorLayoutPrivate::calculateGraphs(Qt::Orientation orientation)
{
#if defined(QT_DEBUG) || defined(QT_BUILD_INTERNAL)
    lastCalculationUsedSimplex[orientation] = false;
#endif

    static bool simplificationEnabled = qEnvironmentVariableIsEmpty("QT_ANCHORLAYOUT_NO_SIMPLIFICATION");

    // Reset the nominal sizes of each anchor based on the current item sizes
    refreshAllSizeHints(orientation);

    // Simplify the graph
    if (simplificationEnabled && !simplifyGraph(orientation)) {
        qWarning("QGraphicsAnchorLayout: anchor setup is not feasible.");
        graphHasConflicts[orientation] = true;
        return;
    }

    // Traverse all graph edges and store the possible paths to each vertex
    findPaths(orientation);

    // From the paths calculated above, extract the constraints that the current
    // anchor setup impose, to our Linear Programming problem.
    constraintsFromPaths(orientation);

    // Split the constraints and anchors into groups that should be fed to the
    // simplex solver independently. Currently we find two groups:
    //
    //  1) The "trunk", that is, the set of anchors (items) that are connected
    //     to the two opposite sides of our layout, and thus need to stretch in
    //     order to fit in the current layout size.
    //
    //  2) The floating or semi-floating anchors (items) that are those which
    //     are connected to only one (or none) of the layout sides, thus are not
    //     influenced by the layout size.
    const auto parts = getGraphParts(orientation);

    // Now run the simplex solver to calculate Minimum, Preferred and Maximum sizes
    // of the "trunk" set of constraints and variables.
    // ### does trunk always exist? empty = trunk is the layout left->center->right
    const QList<AnchorData *> trunkVariables = getVariables(parts.trunkConstraints);

    // For minimum and maximum, use the path between the two layout sides as the
    // objective function.
    AnchorVertex *v = layoutLastVertex[orientation];
    GraphPath trunkPath = graphPaths[orientation].value(v);

    bool feasible = calculateTrunk(orientation, trunkPath, parts.trunkConstraints, trunkVariables);

    // For the other parts that not the trunk, solve only for the preferred size
    // that is the size they will remain at, since they are not stretched by the
    // layout.

    if (feasible && !parts.nonTrunkConstraints.isEmpty()) {
        const QList<AnchorData *> partVariables = getVariables(parts.nonTrunkConstraints);
        Q_ASSERT(!partVariables.isEmpty());
        feasible = calculateNonTrunk(parts.nonTrunkConstraints, partVariables);
    }

    // Propagate the new sizes down the simplified graph, ie. tell the
    // group anchors to set their children anchors sizes.
    updateAnchorSizes(orientation);

    graphHasConflicts[orientation] = !feasible;

    // Clean up our data structures. They are not needed anymore since
    // distribution uses just interpolation.
    qDeleteAll(constraints[orientation]);
    constraints[orientation].clear();
    graphPaths[orientation].clear(); // ###

    if (simplificationEnabled)
        restoreSimplifiedGraph(orientation);
}

/*!
    \internal

    Shift all the constraints by a certain amount. This allows us to deal with negative values in
    the linear program if they are bounded by a certain limit. Functions should be careful to
    call it again with a negative amount, to shift the constraints back.
*/
static void shiftConstraints(const QList<QSimplexConstraint *> &constraints, qreal amount)
{
    for (int i = 0; i < constraints.count(); ++i) {
        QSimplexConstraint *c = constraints.at(i);
        const qreal multiplier = std::accumulate(c->variables.cbegin(), c->variables.cend(), qreal(0));
        c->constant += multiplier * amount;
    }
}

/*!
    \internal

    Calculate the sizes for all anchors which are part of the trunk. This works
    on top of a (possibly) simplified graph.
*/
bool QGraphicsAnchorLayoutPrivate::calculateTrunk(Qt::Orientation orientation, const GraphPath &path,
                                                  const QList<QSimplexConstraint *> &constraints,
                                                  const QList<AnchorData *> &variables)
{
    bool feasible = true;
    bool needsSimplex = !constraints.isEmpty();

#if 0
    qDebug("Simplex %s for trunk of %s", needsSimplex ? "used" : "NOT used",
           orientation == Qt::Horizontal ? "Horizontal" : "Vertical");
#endif

    if (needsSimplex) {

        QList<QSimplexConstraint *> sizeHintConstraints = constraintsFromSizeHints(variables);
        QList<QSimplexConstraint *> allConstraints = constraints + sizeHintConstraints;

        shiftConstraints(allConstraints, g_offset);

        // Solve min and max size hints
        qreal min, max;
        feasible = solveMinMax(allConstraints, path, &min, &max);

        if (feasible) {
            solvePreferred(constraints, variables);

            // Calculate and set the preferred size for the layout,
            // from the edge sizes that were calculated above.
            qreal pref(0.0);
            for (const AnchorData *ad : path.positives)
                pref += ad->sizeAtPreferred;
            for (const AnchorData *ad : path.negatives)
                pref -= ad->sizeAtPreferred;

            sizeHints[orientation][Qt::MinimumSize] = min;
            sizeHints[orientation][Qt::PreferredSize] = pref;
            sizeHints[orientation][Qt::MaximumSize] = max;
        }

        qDeleteAll(sizeHintConstraints);
        shiftConstraints(constraints, -g_offset);

    } else {
        // No Simplex is necessary because the path was simplified all the way to a single
        // anchor.
        Q_ASSERT(path.positives.count() == 1);
        Q_ASSERT(path.negatives.count() == 0);

        AnchorData *ad = *path.positives.cbegin();
        ad->sizeAtMinimum = ad->minSize;
        ad->sizeAtPreferred = ad->prefSize;
        ad->sizeAtMaximum = ad->maxSize;

        sizeHints[orientation][Qt::MinimumSize] = ad->sizeAtMinimum;
        sizeHints[orientation][Qt::PreferredSize] = ad->sizeAtPreferred;
        sizeHints[orientation][Qt::MaximumSize] = ad->sizeAtMaximum;
    }

#if defined(QT_DEBUG) || defined(QT_BUILD_INTERNAL)
    lastCalculationUsedSimplex[orientation] = needsSimplex;
#endif

    return feasible;
}

/*!
    \internal
*/
bool QGraphicsAnchorLayoutPrivate::calculateNonTrunk(const QList<QSimplexConstraint *> &constraints,
                                                     const QList<AnchorData *> &variables)
{
    shiftConstraints(constraints, g_offset);
    bool feasible = solvePreferred(constraints, variables);

    if (feasible) {
        // Propagate size at preferred to other sizes. Semi-floats always will be
        // in their sizeAtPreferred.
        for (int j = 0; j < variables.count(); ++j) {
            AnchorData *ad = variables.at(j);
            Q_ASSERT(ad);
            ad->sizeAtMinimum = ad->sizeAtPreferred;
            ad->sizeAtMaximum = ad->sizeAtPreferred;
        }
    }

    shiftConstraints(constraints, -g_offset);
    return feasible;
}

/*!
    \internal

    Traverse the graph refreshing the size hints. Edges will query their associated
    item or graphicsAnchor for their size hints.
*/
void QGraphicsAnchorLayoutPrivate::refreshAllSizeHints(Qt::Orientation orientation)
{
    Graph<AnchorVertex, AnchorData> &g = graph[orientation];
    QList<QPair<AnchorVertex *, AnchorVertex *>> vertices = g.connections();

    QLayoutStyleInfo styleInf = styleInfo();
    for (int i = 0; i < vertices.count(); ++i) {
        AnchorData *data = g.edgeData(vertices.at(i).first, vertices.at(i).second);
        data->refreshSizeHints(&styleInf);
    }
}

/*!
  \internal

  This method walks the graph using a breadth-first search to find paths
  between the root vertex and each vertex on the graph. The edges
  directions in each path are considered and they are stored as a
  positive edge (left-to-right) or negative edge (right-to-left).

  The list of paths is used later to generate a list of constraints.
 */
void QGraphicsAnchorLayoutPrivate::findPaths(Qt::Orientation orientation)
{
    QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue;

    QSet<AnchorData *> visited;

    AnchorVertex *root = layoutFirstVertex[orientation];

    graphPaths[orientation].insert(root, GraphPath());

    const auto adjacentVertices = graph[orientation].adjacentVertices(root);
    for (AnchorVertex *v : adjacentVertices)
        queue.enqueue(qMakePair(root, v));

    while(!queue.isEmpty()) {
        QPair<AnchorVertex *, AnchorVertex *>  pair = queue.dequeue();
        AnchorData *edge = graph[orientation].edgeData(pair.first, pair.second);

        if (visited.contains(edge))
            continue;

        visited.insert(edge);
        GraphPath current = graphPaths[orientation].value(pair.first);

        if (edge->from == pair.first)
            current.positives.insert(edge);
        else
            current.negatives.insert(edge);

        graphPaths[orientation].insert(pair.second, current);

        const auto adjacentVertices = graph[orientation].adjacentVertices(pair.second);
        for (AnchorVertex *v : adjacentVertices)
            queue.enqueue(qMakePair(pair.second, v));
    }

    // We will walk through every reachable items (non-float) store them in a temporary set.
    // We them create a set of all items and subtract the non-floating items from the set in
    // order to get the floating items. The floating items is then stored in m_floatItems
    identifyFloatItems(visited, orientation);
}

/*!
  \internal

  Each vertex on the graph that has more than one path to it
  represents a contra int to the sizes of the items in these paths.

  This method walks the list of paths to each vertex, generate
  the constraints and store them in a list so they can be used later
  by the Simplex solver.
*/
void QGraphicsAnchorLayoutPrivate::constraintsFromPaths(Qt::Orientation orientation)
{
    const auto vertices = graphPaths[orientation].uniqueKeys();
    for (AnchorVertex *vertex : vertices) {
        int valueCount = graphPaths[orientation].count(vertex);
        if (valueCount == 1)
            continue;

        QList<GraphPath> pathsToVertex = graphPaths[orientation].values(vertex);
        for (int i = 1; i < valueCount; ++i) {
            constraints[orientation] += \
                pathsToVertex[0].constraint(pathsToVertex.at(i));
        }
    }
}

/*!
  \internal
*/
void QGraphicsAnchorLayoutPrivate::updateAnchorSizes(Qt::Orientation orientation)
{
    Graph<AnchorVertex, AnchorData> &g = graph[orientation];
    const QList<QPair<AnchorVertex *, AnchorVertex *>> &vertices = g.connections();

    for (int i = 0; i < vertices.count(); ++i) {
        AnchorData *ad = g.edgeData(vertices.at(i).first, vertices.at(i).second);
        ad->updateChildrenSizes();
    }
}

/*!
  \internal

  Create LP constraints for each anchor based on its minimum and maximum
  sizes, as specified in its size hints
*/
QList<QSimplexConstraint *> QGraphicsAnchorLayoutPrivate::constraintsFromSizeHints(
    const QList<AnchorData *> &anchors)
{
    if (anchors.isEmpty())
        return QList<QSimplexConstraint *>();

    // Look for the layout edge. That can be either the first half in case the
    // layout is split in two, or the whole layout anchor.
    const Qt::Orientation orient = anchors.first()->isVertical ? Qt::Vertical : Qt::Horizontal;
    AnchorData *layoutEdge = nullptr;
    if (layoutCentralVertex[orient]) {
        layoutEdge = graph[orient].edgeData(layoutFirstVertex[orient], layoutCentralVertex[orient]);
    } else {
        layoutEdge = graph[orient].edgeData(layoutFirstVertex[orient], layoutLastVertex[orient]);
    }

    // If maxSize is less then "infinite", that means there are other anchors
    // grouped together with this one. We can't ignore its maximum value so we
    // set back the variable to NULL to prevent the continue condition from being
    // satisfied in the loop below.
    const qreal expectedMax = layoutCentralVertex[orient] ? QWIDGETSIZE_MAX / 2 : QWIDGETSIZE_MAX;
    qreal actualMax;
    if (layoutEdge->from == layoutFirstVertex[orient]) {
        actualMax = layoutEdge->maxSize;
    } else {
        actualMax = -layoutEdge->minSize;
    }
    if (actualMax != expectedMax) {
        layoutEdge = nullptr;
    }

    // For each variable, create constraints based on size hints
    QList<QSimplexConstraint *> anchorConstraints;
    bool unboundedProblem = true;
    for (int i = 0; i < anchors.size(); ++i) {
        AnchorData *ad = anchors.at(i);

        // Anchors that have their size directly linked to another one don't need constraints
        // For exammple, the second half of an item has exactly the same size as the first half
        // thus constraining the latter is enough.
        if (ad->dependency == AnchorData::Slave)
            continue;

        // To use negative variables inside simplex, we shift them so the minimum negative value is
        // mapped to zero before solving. To make sure that it works, we need to guarantee that the
        // variables are all inside a certain boundary.
        qreal boundedMin = qBound(-g_offset, ad->minSize, g_offset);
        qreal boundedMax = qBound(-g_offset, ad->maxSize, g_offset);

        if ((boundedMin == boundedMax) || qFuzzyCompare(boundedMin, boundedMax)) {
            QSimplexConstraint *c = new QSimplexConstraint;
            c->variables.insert(ad, 1.0);
            c->constant = boundedMin;
            c->ratio = QSimplexConstraint::Equal;
            anchorConstraints += c;
            unboundedProblem = false;
        } else {
            QSimplexConstraint *c = new QSimplexConstraint;
            c->variables.insert(ad, 1.0);
            c->constant = boundedMin;
            c->ratio = QSimplexConstraint::MoreOrEqual;
            anchorConstraints += c;

            // We avoid adding restrictions to the layout internal anchors. That's
            // to prevent unnecessary fair distribution from happening due to this
            // artificial restriction.
            if (ad == layoutEdge)
                continue;

            c = new QSimplexConstraint;
            c->variables.insert(ad, 1.0);
            c->constant = boundedMax;
            c->ratio = QSimplexConstraint::LessOrEqual;
            anchorConstraints += c;
            unboundedProblem = false;
        }
    }

    // If no upper boundary restriction was added, add one to avoid unbounded problem
    if (unboundedProblem) {
        QSimplexConstraint *c = new QSimplexConstraint;
        c->variables.insert(layoutEdge, 1.0);
        // The maximum size that the layout can take
        c->constant = g_offset;
        c->ratio = QSimplexConstraint::LessOrEqual;
        anchorConstraints += c;
    }

    return anchorConstraints;
}

/*!
  \internal
*/
QGraphicsAnchorLayoutPrivate::GraphParts
QGraphicsAnchorLayoutPrivate::getGraphParts(Qt::Orientation orientation)
{
    GraphParts result;

    Q_ASSERT(layoutFirstVertex[orientation] && layoutLastVertex[orientation]);

    AnchorData *edgeL1 = nullptr;
    AnchorData *edgeL2 = nullptr;

    // The layout may have a single anchor between Left and Right or two half anchors
    // passing through the center
    if (layoutCentralVertex[orientation]) {
        edgeL1 = graph[orientation].edgeData(layoutFirstVertex[orientation], layoutCentralVertex[orientation]);
        edgeL2 = graph[orientation].edgeData(layoutCentralVertex[orientation], layoutLastVertex[orientation]);
    } else {
        edgeL1 = graph[orientation].edgeData(layoutFirstVertex[orientation], layoutLastVertex[orientation]);
    }

    result.nonTrunkConstraints = constraints[orientation] + itemCenterConstraints[orientation];

    QSet<QSimplexVariable *> trunkVariables;

    trunkVariables += edgeL1;
    if (edgeL2)
        trunkVariables += edgeL2;

    bool dirty;
    auto end = result.nonTrunkConstraints.end();
    do {
        dirty = false;

        auto isMatch = [&result, &trunkVariables](QSimplexConstraint *c) -> bool {
            bool match = false;

            // Check if this constraint have some overlap with current
            // trunk variables...
            for (QSimplexVariable *ad : qAsConst(trunkVariables)) {
                if (c->variables.contains(ad)) {
                    match = true;
                    break;
                }
            }

            // If so, we add it to trunk, and erase it from the
            // remaining constraints.
            if (match) {
                result.trunkConstraints += c;
                for (auto jt = c->variables.cbegin(), end = c->variables.cend(); jt != end; ++jt)
                    trunkVariables.insert(jt.key());
                return true;
            } else {
                // Note that we don't erase the constraint if it's not
                // a match, since in a next iteration of a do-while we
                // can pass on it again and it will be a match.
                //
                // For example: if trunk share a variable with
                // remainingConstraints[1] and it shares with
                // remainingConstraints[0], we need a second iteration
                // of the do-while loop to match both.
                return false;
            }
        };
        const auto newEnd = std::remove_if(result.nonTrunkConstraints.begin(), end, isMatch);
        dirty = newEnd != end;
        end = newEnd;
    } while (dirty);

    result.nonTrunkConstraints.erase(end, result.nonTrunkConstraints.end());

    return result;
}

/*!
 \internal

  Use all visited Anchors on findPaths() so we can identify non-float Items.
*/
void QGraphicsAnchorLayoutPrivate::identifyFloatItems(const QSet<AnchorData *> &visited, Qt::Orientation orientation)
{
    QSet<QGraphicsLayoutItem *> nonFloating;

    for (const AnchorData *ad : visited)
        identifyNonFloatItems_helper(ad, &nonFloating);

    QSet<QGraphicsLayoutItem *> floatItems;
    for (QGraphicsLayoutItem *item : qAsConst(items)) {
        if (!nonFloating.contains(item))
            floatItems.insert(item);
    }
    m_floatItems[orientation] = std::move(floatItems);
}


/*!
 \internal

  Given an anchor, if it is an internal anchor and Normal we must mark it's item as non-float.
  If the anchor is Sequential or Parallel, we must iterate on its children recursively until we reach
  internal anchors (items).
*/
void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems_helper(const AnchorData *ad, QSet<QGraphicsLayoutItem *> *nonFloatingItemsIdentifiedSoFar)
{
    Q_Q(QGraphicsAnchorLayout);

    switch(ad->type) {
    case AnchorData::Normal:
        if (ad->item && ad->item != q)
            nonFloatingItemsIdentifiedSoFar->insert(ad->item);
        break;
    case AnchorData::Sequential:
        foreach (const AnchorData *d, static_cast<const SequentialAnchorData *>(ad)->m_edges)
            identifyNonFloatItems_helper(d, nonFloatingItemsIdentifiedSoFar);
        break;
    case AnchorData::Parallel:
        identifyNonFloatItems_helper(static_cast<const ParallelAnchorData *>(ad)->firstEdge, nonFloatingItemsIdentifiedSoFar);
        identifyNonFloatItems_helper(static_cast<const ParallelAnchorData *>(ad)->secondEdge, nonFloatingItemsIdentifiedSoFar);
        break;
    }
}

/*!
  \internal

  Use the current vertices distance to calculate and set the geometry of
  each item.
*/
void QGraphicsAnchorLayoutPrivate::setItemsGeometries(const QRectF &geom)
{
    Q_Q(QGraphicsAnchorLayout);
    AnchorVertex *firstH, *secondH, *firstV, *secondV;

    qreal top;
    qreal left;
    qreal right;

    q->getContentsMargins(&left, &top, &right, nullptr);
    const Qt::LayoutDirection visualDir = visualDirection();
    if (visualDir == Qt::RightToLeft)
        qSwap(left, right);

    left += geom.left();
    top += geom.top();
    right = geom.right() - right;

    for (QGraphicsLayoutItem *item : qAsConst(items)) {
        QRectF newGeom;
        QSizeF itemPreferredSize = item->effectiveSizeHint(Qt::PreferredSize);
        if (m_floatItems[Qt::Horizontal].contains(item)) {
            newGeom.setLeft(0);
            newGeom.setRight(itemPreferredSize.width());
        } else {
            firstH = internalVertex(item, Qt::AnchorLeft);
            secondH = internalVertex(item, Qt::AnchorRight);

            if (visualDir == Qt::LeftToRight) {
                newGeom.setLeft(left + firstH->distance);
                newGeom.setRight(left + secondH->distance);
            } else {
                newGeom.setLeft(right - secondH->distance);
                newGeom.setRight(right - firstH->distance);
            }
        }

        if (m_floatItems[Qt::Vertical].contains(item)) {
            newGeom.setTop(0);
            newGeom.setBottom(itemPreferredSize.height());
        } else {
            firstV = internalVertex(item, Qt::AnchorTop);
            secondV = internalVertex(item, Qt::AnchorBottom);

            newGeom.setTop(top + firstV->distance);
            newGeom.setBottom(top + secondV->distance);
        }

        item->setGeometry(newGeom);
    }
}

/*!
  \internal

  Calculate the position of each vertex based on the paths to each of
  them as well as the current edges sizes.
*/
void QGraphicsAnchorLayoutPrivate::calculateVertexPositions(Qt::Orientation orientation)
{
    QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue;
    QSet<AnchorVertex *> visited;

    // Get root vertex
    AnchorVertex *root = layoutFirstVertex[orientation];

    root->distance = 0;
    visited.insert(root);

    // Add initial edges to the queue
    const auto adjacentVertices = graph[orientation].adjacentVertices(root);
    for (AnchorVertex *v : adjacentVertices)
        queue.enqueue(qMakePair(root, v));

    // Do initial calculation required by "interpolateEdge()"
    setupEdgesInterpolation(orientation);

    // Traverse the graph and calculate vertex positions
    while (!queue.isEmpty()) {
        QPair<AnchorVertex *, AnchorVertex *> pair = queue.dequeue();
        AnchorData *edge = graph[orientation].edgeData(pair.first, pair.second);

        if (visited.contains(pair.second))
            continue;

        visited.insert(pair.second);
        interpolateEdge(pair.first, edge);

        QList<AnchorVertex *> adjacents = graph[orientation].adjacentVertices(pair.second);
        for (int i = 0; i < adjacents.count(); ++i) {
            if (!visited.contains(adjacents.at(i)))
                queue.enqueue(qMakePair(pair.second, adjacents.at(i)));
        }
    }
}

/*!
  \internal

  Calculate interpolation parameters based on current Layout Size.
  Must be called once before calling "interpolateEdgeSize()" for
  the edges.
*/
void QGraphicsAnchorLayoutPrivate::setupEdgesInterpolation(
    Qt::Orientation orientation)
{
    Q_Q(QGraphicsAnchorLayout);

    qreal current;
    current = (orientation == Qt::Horizontal) ? q->contentsRect().width() : q->contentsRect().height();

    QPair<Interval, qreal> result;
    result = getFactor(current,
                       sizeHints[orientation][Qt::MinimumSize],
                       sizeHints[orientation][Qt::PreferredSize],
                       sizeHints[orientation][Qt::PreferredSize],
                       sizeHints[orientation][Qt::PreferredSize],
                       sizeHints[orientation][Qt::MaximumSize]);

    interpolationInterval[orientation] = result.first;
    interpolationProgress[orientation] = result.second;
}

/*!
    \internal

    Calculate the current Edge size based on the current Layout size and the
    size the edge is supposed to have when the layout is at its:

    - minimum size,
    - preferred size,
    - maximum size.

    These three key values are calculated in advance using linear
    programming (more expensive) or the simplification algorithm, then
    subsequential resizes of the parent layout require a simple
    interpolation.
*/
void QGraphicsAnchorLayoutPrivate::interpolateEdge(AnchorVertex *base, AnchorData *edge)
{
    const Qt::Orientation orientation = edge->isVertical ? Qt::Vertical : Qt::Horizontal;
    const QPair<Interval, qreal> factor(interpolationInterval[orientation],
                                        interpolationProgress[orientation]);

    qreal edgeDistance = interpolate(factor, edge->sizeAtMinimum, edge->sizeAtPreferred,
                                     edge->sizeAtPreferred, edge->sizeAtPreferred,
                                     edge->sizeAtMaximum);

    Q_ASSERT(edge->from == base || edge->to == base);

    // Calculate the distance for the vertex opposite to the base
    if (edge->from == base) {
        edge->to->distance = base->distance + edgeDistance;
    } else {
        edge->from->distance = base->distance - edgeDistance;
    }
}

bool QGraphicsAnchorLayoutPrivate::solveMinMax(const QList<QSimplexConstraint *> &constraints,
                                               const GraphPath &path, qreal *min, qreal *max)
{
    QSimplex simplex;
    bool feasible = simplex.setConstraints(constraints);
    if (feasible) {
        // Obtain the objective constraint
        QSimplexConstraint objective;
        QSet<AnchorData *>::const_iterator iter;
        for (iter = path.positives.constBegin(); iter != path.positives.constEnd(); ++iter)
            objective.variables.insert(*iter, 1.0);

        for (iter = path.negatives.constBegin(); iter != path.negatives.constEnd(); ++iter)
            objective.variables.insert(*iter, -1.0);

        const qreal objectiveOffset = (path.positives.count() - path.negatives.count()) * g_offset;
        simplex.setObjective(&objective);

        // Calculate minimum values
        *min = simplex.solveMin() - objectiveOffset;

        // Save sizeAtMinimum results
        QList<AnchorData *> variables = getVariables(constraints);
        for (int i = 0; i < variables.size(); ++i) {
            AnchorData *ad = static_cast<AnchorData *>(variables.at(i));
            ad->sizeAtMinimum = ad->result - g_offset;
        }

        // Calculate maximum values
        *max = simplex.solveMax() - objectiveOffset;

        // Save sizeAtMaximum results
        for (int i = 0; i < variables.size(); ++i) {
            AnchorData *ad = static_cast<AnchorData *>(variables.at(i));
            ad->sizeAtMaximum = ad->result - g_offset;
        }
    }
    return feasible;
}

enum slackType { Grower = -1, Shrinker = 1 };
static QPair<QSimplexVariable *, QSimplexConstraint *> createSlack(QSimplexConstraint *sizeConstraint,
                                                                   qreal interval, slackType type)
{
    QSimplexVariable *slack = new QSimplexVariable;
    sizeConstraint->variables.insert(slack, type);

    QSimplexConstraint *limit = new QSimplexConstraint;
    limit->variables.insert(slack, 1.0);
    limit->ratio = QSimplexConstraint::LessOrEqual;
    limit->constant = interval;

    return qMakePair(slack, limit);
}

bool QGraphicsAnchorLayoutPrivate::solvePreferred(const QList<QSimplexConstraint *> &constraints,
                                                  const QList<AnchorData *> &variables)
{
    QList<QSimplexConstraint *> preferredConstraints;
    QList<QSimplexVariable *> preferredVariables;
    QSimplexConstraint objective;

    // Fill the objective coefficients for this variable. In the
    // end the objective function will be
    //
    //     z = n * (A_shrinker_hard + A_grower_hard + B_shrinker_hard + B_grower_hard + ...) +
    //             (A_shrinker_soft + A_grower_soft + B_shrinker_soft + B_grower_soft + ...)
    //
    // where n is the number of variables that have
    // slacks. Note that here we use the number of variables
    // as coefficient, this is to mark the "shrinker slack
    // variable" less likely to get value than the "grower
    // slack variable".

    // This will fill the values for the structural constraints
    // and we now fill the values for the slack constraints (one per variable),
    // which have this form (the constant A_pref was set when creating the slacks):
    //
    //      A + A_shrinker_hard + A_shrinker_soft - A_grower_hard - A_grower_soft = A_pref
    //
    for (int i = 0; i < variables.size(); ++i) {
        AnchorData *ad = variables.at(i);

        // The layout original structure anchors are not relevant in preferred size calculation
        if (ad->isLayoutAnchor)
            continue;

        // By default, all variables are equal to their preferred size. If they have room to
        // grow or shrink, such flexibility will be added by the additional variables below.
        QSimplexConstraint *sizeConstraint = new QSimplexConstraint;
        preferredConstraints += sizeConstraint;
        sizeConstraint->variables.insert(ad, 1.0);
        sizeConstraint->constant = ad->prefSize + g_offset;

        // Can easily shrink
        QPair<QSimplexVariable *, QSimplexConstraint *> slack;
        const qreal softShrinkInterval = ad->prefSize - ad->minPrefSize;
        if (softShrinkInterval) {
            slack = createSlack(sizeConstraint, softShrinkInterval, Shrinker);
            preferredVariables += slack.first;
            preferredConstraints += slack.second;

            // Add to objective with ratio == 1 (soft)
            objective.variables.insert(slack.first, 1.0);
        }

        // Can easily grow
        const qreal softGrowInterval = ad->maxPrefSize - ad->prefSize;
        if (softGrowInterval) {
            slack = createSlack(sizeConstraint, softGrowInterval, Grower);
            preferredVariables += slack.first;
            preferredConstraints += slack.second;

            // Add to objective with ratio == 1 (soft)
            objective.variables.insert(slack.first, 1.0);
        }

        // Can shrink if really necessary
        const qreal hardShrinkInterval = ad->minPrefSize - ad->minSize;
        if (hardShrinkInterval) {
            slack = createSlack(sizeConstraint, hardShrinkInterval, Shrinker);
            preferredVariables += slack.first;
            preferredConstraints += slack.second;

            // Add to objective with ratio == N (hard)
            objective.variables.insert(slack.first, variables.size());
        }

        // Can grow if really necessary
        const qreal hardGrowInterval = ad->maxSize - ad->maxPrefSize;
        if (hardGrowInterval) {
            slack = createSlack(sizeConstraint, hardGrowInterval, Grower);
            preferredVariables += slack.first;
            preferredConstraints += slack.second;

            // Add to objective with ratio == N (hard)
            objective.variables.insert(slack.first, variables.size());
        }
    }

    QSimplex *simplex = new QSimplex;
    bool feasible = simplex->setConstraints(constraints + preferredConstraints);
    if (feasible) {
        simplex->setObjective(&objective);

        // Calculate minimum values
        simplex->solveMin();

        // Save sizeAtPreferred results
        for (int i = 0; i < variables.size(); ++i) {
            AnchorData *ad = variables.at(i);
            ad->sizeAtPreferred = ad->result - g_offset;
        }
    }

    // Make sure we delete the simplex solver -before- we delete the
    // constraints used by it.
    delete simplex;

    // Delete constraints and variables we created.
    qDeleteAll(preferredConstraints);
    qDeleteAll(preferredVariables);

    return feasible;
}

/*!
    \internal
    Returns \c true if there are no arrangement that satisfies all constraints.
    Otherwise returns \c false.

    \sa addAnchor()
*/
bool QGraphicsAnchorLayoutPrivate::hasConflicts() const
{
    QGraphicsAnchorLayoutPrivate *that = const_cast<QGraphicsAnchorLayoutPrivate*>(this);
    that->calculateGraphs();

    bool floatConflict = !m_floatItems[Qt::Horizontal].isEmpty() || !m_floatItems[Qt::Vertical].isEmpty();

    return graphHasConflicts[Qt::Horizontal] || graphHasConflicts[Qt::Vertical] || floatConflict;
}

#ifdef QT_DEBUG
void QGraphicsAnchorLayoutPrivate::dumpGraph(const QString &name)
{
    QFile file(QString::fromLatin1("anchorlayout.%1.dot").arg(name));
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
        qWarning("Could not write to %ls", qUtf16Printable(file.fileName()));

    QString str = QString::fromLatin1("digraph anchorlayout {\nnode [shape=\"rect\"]\n%1}");
    QString dotContents = graph[Qt::Horizontal].serializeToDot();
    dotContents += graph[Qt::Vertical].serializeToDot();
    file.write(str.arg(dotContents).toLocal8Bit());

    file.close();
}
#endif

QT_END_NAMESPACE
