/*!
  \file
  \brief 複数サーフェスの合成

  \author Satofumi KAMIMURA

  $Id: MultiSurface.cpp 1811 2010-04-30 16:12:05Z satofumi $
*/

#include "MultiSurface.h"
#include <boost/bind.hpp>
#include <algorithm>
#include <vector>

using namespace qrk;
using namespace boost;
using namespace std;


namespace
{
    typedef vector<Surface*> Surfaces;
    typedef vector<Point<long> > Points;
}


struct MultiSurface::pImpl
{
    Surface& base_surface_;
    Surfaces surfaces_;
    Points offsets_;
    vector<float> alphas_;


    pImpl(Surface& base_surface) : base_surface_(base_surface)
    {
    }


    void draw(const Rect<long>* src, const Rect<long>* dest)
    {
        base_surface_.draw(src, dest);

        // 全て描画
        size_t n = surfaces_.size();
        for (size_t i = 0; i < n; ++i) {
            Point<long>& offset = offsets_[i];
            Surface*& surface = surfaces_[i];
            Rect<long> draw_point = surface->rect();
            draw_point.x = dest->x + offset.x;
            draw_point.y = dest->y + offset.y;

            surface->draw(src, &draw_point);
        }
    }
};


MultiSurface::MultiSurface(Surface& base_surface)
    : pimpl(new pImpl(base_surface))
{
}


MultiSurface::~MultiSurface(void)
{
}


bool MultiSurface::isValid(void) const
{
    return pimpl->base_surface_.isValid();
}


Rect<long> MultiSurface::rect(void) const
{
    return pimpl->base_surface_.rect();
}


void MultiSurface::setAlpha(float alpha)
{
#if 1
    size_t n = pimpl->surfaces_.size();
    for (size_t i = 0; i < n; ++i) {
        float surface_alpha = alpha * pimpl->alphas_[i];
        pimpl->surfaces_[i]->setAlpha(surface_alpha);
    }

#else
    pimpl->base_surface_.setAlpha(alpha);

    // 登録済みのサーフェスに適用
    for_each(pimpl->surfaces_.begin(), pimpl->surfaces_.end(),
             bind(&Surface::setAlpha, _1, alpha));
#endif
}


float MultiSurface::alpha(void) const
{
    return pimpl->base_surface_.alpha();
}


void MultiSurface::setRotateAngle(const Angle& angle)
{
    (void)angle;
    // !!!
}


void MultiSurface::draw(const Rect<long>* src, const Rect<long>* dest)
{
    pimpl->draw(src, dest);
}


void MultiSurface::push_front(Surface& surface, const Point<long>& offset)
{
    pimpl->surfaces_.push_back(&surface);
    pimpl->offsets_.push_back(offset);
    pimpl->alphas_.push_back(surface.alpha());
}
