#include "fab.h"
#include <QPainter>
#include <QGraphicsDropShadowEffect>
#include "fab_p.h"

FloatingActionButtonPrivate::FloatingActionButtonPrivate(FloatingActionButton *q)
    : RaisedButtonPrivate(q),
      mini(false),
      offsX(34),
      offsY(36),
      corner(Qt::BottomRightCorner)
{
}

FloatingActionButtonPrivate::~FloatingActionButtonPrivate()
{
}

void FloatingActionButtonPrivate::init()
{
    Q_Q(FloatingActionButton);

    q->setRole(Material::Primary);
    q->setFixedSize(56, 56);
    q->setGeometry(fabGeometry());

    assignAnimationProperties();

    QPainterPath path;
    path.addEllipse(0, 0, 56, 56);
    ripple->setClipPath(path);
    ripple->setClipping(true);
}

QRect FloatingActionButtonPrivate::fabGeometry() const
{
    Q_Q(const FloatingActionButton);

    QWidget *parent = q->parentWidget();
    if (!parent)
        return QRect();

    const int s = mini ? 40 : 56;

    switch (corner)
    {
    case Qt::TopLeftCorner:
        return QRect(offsX,
                     offsY,
                     s, s);
    case Qt::TopRightCorner:
        return QRect(parent->width() - (offsX + s),
                     offsY,
                     s, s);
    case Qt::BottomLeftCorner:
        return QRect(offsX,
                     parent->height() - (offsY + s),
                     s, s);
    case Qt::BottomRightCorner:
    default:
        return QRect(parent->width() - (offsX + s),
                     parent->height() - (offsY + s),
                     s, s);
    }
}

void FloatingActionButtonPrivate::assignAnimationProperties()
{
    if (mini)
    {
        effect->setColor(QColor(0, 0, 0, 80));

        normalState->assignProperty(effect, "offset", QPointF(0, 3));
        normalState->assignProperty(effect, "blurRadius", 13);
        pressedState->assignProperty(effect, "offset", QPointF(0, 7));
        pressedState->assignProperty(effect, "blurRadius", 20);
    }
    else
    {
        effect->setColor(QColor(0, 0, 0, 110));

        normalState->assignProperty(effect, "offset", QPointF(0, 6));
        normalState->assignProperty(effect, "blurRadius", 16);
        pressedState->assignProperty(effect, "offset", QPointF(0, 11));
        pressedState->assignProperty(effect, "blurRadius", 28);
    }
}

FloatingActionButton::FloatingActionButton(const QIcon &icon, QWidget *parent)
    : RaisedButton(*new FloatingActionButtonPrivate(this), parent)
{
    d_func()->init();

    setIcon(icon);
}

FloatingActionButton::~FloatingActionButton()
{
}

QSize FloatingActionButton::sizeHint() const
{
    Q_D(const FloatingActionButton);

    if (d->mini) {
        return QSize(40, 40);
    }
    return QSize(56, 56);
}

void FloatingActionButton::setMini(bool state)
{
    Q_D(FloatingActionButton);

    if (d->mini == state)
        return;

    d->mini = state;

    const int s = state ? 40 : 56;

    setFixedSize(s, s);
    QPainterPath path;
    path.addEllipse(0, 0, s, s);
    d->ripple->setClipPath(path);

    d->assignAnimationProperties();
    update();
}

bool FloatingActionButton::isMini() const
{
    Q_D(const FloatingActionButton);

    return d->mini;
}

void FloatingActionButton::setCorner(Qt::Corner corner)
{
    Q_D(FloatingActionButton);

    if (d->corner == corner)
        return;

    d->corner = corner;
    update();
}

Qt::Corner FloatingActionButton::corner() const
{
    Q_D(const FloatingActionButton);

    return d->corner;
}

void FloatingActionButton::setOffset(int x, int y)
{
    Q_D(FloatingActionButton);

    d->offsX = x;
    d->offsY = y;
    update();
}

QSize FloatingActionButton::offset() const
{
    Q_D(const FloatingActionButton);

    return QSize(d->offsX, d->offsY);
}

void FloatingActionButton::setXOffset(int x)
{
    Q_D(FloatingActionButton);

    d->offsX = x;
    update();
}

int FloatingActionButton::xOffset() const
{
    Q_D(const FloatingActionButton);

    return d->offsX;
}

void FloatingActionButton::setYOffset(int y)
{
    Q_D(FloatingActionButton);

    d->offsY = y;
    update();
}

int FloatingActionButton::yOffset() const
{
    Q_D(const FloatingActionButton);

    return d->offsY;
}

bool FloatingActionButton::event(QEvent *event)
{
    switch (event->type())
    {
    case QEvent::ParentChange:
    {
        if (!parent())
            break;

        Q_D(FloatingActionButton);

        parent()->installEventFilter(this);
        setGeometry(d->fabGeometry());
        break;
    }
    case QEvent::ParentAboutToChange:
    {
        if (!parent())
            break;

        parent()->removeEventFilter(this);
        break;
    }
    default:
        break;
    }
    return RaisedButton::event(event);
}

bool FloatingActionButton::eventFilter(QObject *obj, QEvent *event)
{
    QEvent::Type type = event->type();

    if (QEvent::Move == type || QEvent::Resize == type)
    {
        Q_D(FloatingActionButton);

        setGeometry(d->fabGeometry());
    }
    return RaisedButton::eventFilter(obj, event);
}

void FloatingActionButton::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)

    Q_D(FloatingActionButton);

    int s = d->mini ? 40 : 56;

    QRect square = QRect(0, 0, s, s);
    square.moveCenter(rect().center());

    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing);

    QBrush brush;
    brush.setStyle(Qt::SolidPattern);
    brush.setColor(isEnabled()
       ? backgroundColor()
       : disabledTextColor());
    painter.setBrush(brush);
    painter.setPen(Qt::NoPen);

    painter.drawEllipse(square);

    const int sz = d->mini ? 18 : 24;

    QRect iconRect(0, 0, sz, sz);
    iconRect.moveCenter(square.center());

    icon().paint(&painter, iconRect, Qt::AlignCenter, QIcon::Normal);
}
