/*
 * Copyright (C) 2008 Instituto Nokia de Tecnologia. All rights reserved.
 *
 * This file is part of QZion.
 *
 * QZion is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * QZion is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with QZion.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __QZIONIMAGE_P_H__
#define __QZIONIMAGE_P_H__

#include <QGraphicsItem>
#include <QGraphicsPixmapItem>

#include "qzioncommon.h"
#include "qzionrectangle.h"
#include "qgraphicsziongroup.h"


class QZionImagePrivate : public QGraphicsPixmapItem
{
public:
    QZionImage *owner;

    QSize size;
    QColor effectiveColor;
    QImage *buffer, *image;

    inline QZionImagePrivate(QGraphicsItem *parent = 0);
    virtual ~QZionImagePrivate();

    inline void paint(QPainter *painter,
                      const QStyleOptionGraphicsItem *option, QWidget *widget);

    inline void applyColorFilter(QRgb color);
    inline void updateEffectiveColor();

    QGV_MOUSE_EVENT_HANDLERS();
    QGV_EFFECTIVE_SHAPE(QGraphicsPixmapItem);
};


inline QZionImagePrivate::QZionImagePrivate(QGraphicsItem *parent)
    : QGraphicsPixmapItem(parent), effectiveColor(Qt::white),
      buffer(NULL), image(NULL)
{
    setAcceptHoverEvents(true);
    setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
    setTransformationMode(Qt::SmoothTransformation);
    setFlag(QGraphicsItem::ItemClipsToShape, true);
}

inline QZionImagePrivate::~QZionImagePrivate()
{
    delete buffer;
    delete image;
}

inline void QZionImagePrivate::paint(QPainter * painter,
                                     const QStyleOptionGraphicsItem* option,
                                     QWidget* widget)
{
    int opacity = owner->effectiveColor().alpha();

    if (opacity >= 255) {
        QGraphicsPixmapItem::paint(painter, option, widget);
    } else {
        painter->setOpacity(opacity / (float) 255);
        QGraphicsPixmapItem::paint(painter, option, widget);
        painter->setOpacity(1.0);
    }
}

/*! \brief Apply a multiplication color filter to the image

   White filters (default) don't require the expensive color transformations.
   For all other colors we proceed as follows:
     1) Save original image in 'QImage image' so we can restore it when needed.
     2) Create ARGB32 QImage for pixel-to-pixel multiplication.
     3) Fill QImage with filter color.
     4) Apply original image on top of it using Multiply composition mode.
     5) Set pixmap to the new image.

     Original image and work buffer are saved for future use.

   When color processing is no longer needed (aka white filter) we:
     1) Set pixmap to original image.
     2) Free buffers.
 */
inline void QZionImagePrivate::applyColorFilter(QRgb filterRgb)
{
    if (QColor(filterRgb) != Qt::white) {
        if (buffer == NULL) {
            image = new QImage(pixmap().toImage());
            buffer = new QImage(image->size(), QImage::Format_ARGB32_Premultiplied);
        }
        buffer->fill(filterRgb);
        QPainter buffer_painter(buffer);
        buffer_painter.setCompositionMode(QPainter::CompositionMode_Multiply);
        buffer_painter.drawImage(QPoint(0, 0), *image);
        setPixmap(QPixmap::fromImage(*buffer));
    } else {
        setPixmap(QPixmap::fromImage(*image));
        delete buffer;
        buffer = NULL;
        delete image;
        image = NULL;
    }
}

inline void QZionImagePrivate::updateEffectiveColor()
{

    QColor oldEffectiveColor = effectiveColor;
    effectiveColor = owner->clipper() ? owner->clipper()->effectiveColor()
        : Qt::white;

    if (oldEffectiveColor.rgb() != effectiveColor.rgb())
        applyColorFilter(effectiveColor.rgb());
}

#endif
