/*!
  \file
  \brief ルビ付きの部分透過できる文字列サーフェス

  \author Satofumi KAMIMURA

  $Id: TextRubiFadeSurface.cpp 1825 2010-05-15 10:50:09Z satofumi $

  \todo ルビの指定を任意にして、TextFadeSurface を置き換える
  \todo プロポーショナル・フォント以外でも動作するようにする
*/

#include "TextRubiFadeSurface.h"
#include "TextSurface.h"
#include "TextFadeSurface.h"
#include "Font.h"
#include "Utf8.h"
#include "rubi_parse.h"
#include <vector>

using namespace qrk;
using namespace std;


namespace
{
    enum {
        FadeWidthPixel = 200,
    };


    typedef vector<TextSurface*> Surfaces;
}


struct TextRubiFadeSurface::pImpl
{
    TextFadeSurface text_;
    Surfaces rubi_text_;
    vector<long> rubi_x_;
    Rect<long> rect_;
    int rubi_pixel_size_;
    float base_alpha_;
    size_t percent_;


    pImpl(const Font& font, const char* text,
          const Font& rubi_font, const char* kana_only_text)
        : text_(font, text),
          rect_(0, 0, text_.rect().w, text_.rect().h + rubi_font.pixelSize()),
          rubi_pixel_size_(rubi_font.pixelSize()), base_alpha_(1.0),
          percent_(100)
    {
        vector<rubi_t> rubi_positions;
        rubi_parse(rubi_positions, text, kana_only_text);

        // ルビの文字サーフェスを作成
        int kanji_pixel_size = font.pixelSize();
        Utf8 kana_only(kana_only_text);
        for (vector<rubi_t>::const_iterator it = rubi_positions.begin();
             it != rubi_positions.end(); ++it) {

            int kanji_size = kanji_pixel_size * it->kanji_size;
            int rubi_size = rubi_pixel_size_ * it->rubi_size;
            int rubi_space = max(kanji_size - rubi_size, 0);
            int rubi_space_each =
                (it->rubi_size > 1) ? rubi_space / it->rubi_size : 0;
            rubi_size += (it->rubi_size - 1) * rubi_space_each;
            int x_offset = (kanji_size - rubi_size) / 2;
            //fprintf(stderr, "%d, %d, %d, %d, (%d, %d), (%d, %d)\n", x_offset, kanji_size, rubi_size, rubi_space_each, it->rubi_size, rubi_pixel_size_, it->kanji_size, kanji_pixel_size);
            int kanji_base_x =
                kanji_pixel_size * it->kanji_first;

            for (size_t i = 0; i < it->rubi_size; ++i) {
                const string rubi_ch =
                    kana_only.substr(it->rubi_first + i, 1).toStdString();
                TextSurface* surface =
                    new TextSurface(rubi_font, rubi_ch.c_str());
                rubi_text_.push_back(surface);

                // 漢字の位置の対応する位置に、ルビの文字を配置する
                int x = kanji_base_x + x_offset
                    + ((rubi_pixel_size_ + rubi_space_each) * i);
                rubi_x_.push_back(x);
            }
        }

        if (! rubi_x_.empty()) {
            rect_.w = max(text_.rect().w, rubi_x_.back() + rubi_pixel_size_);
        }
    }


    ~pImpl(void)
    {
        for (Surfaces::iterator it = rubi_text_.begin();
             it != rubi_text_.end(); ++it) {
            delete *it;
        }
    }


    void setAlpha(void)
    {
        text_.setFadePercent(percent_);

        int moved_width =
            static_cast<int>((rect_.w + FadeWidthPixel) * percent_ / 100.0);
        int first = -FadeWidthPixel + moved_width;
        int last = 0 + moved_width;

        size_t index = 0;
        for (Surfaces::iterator it = rubi_text_.begin();
             it != rubi_text_.end(); ++it, ++index) {
            Surface* surface = *it;

            float alpha = 1.0;
            int x = rubi_x_[index];
            x = max(x, 0);
            if (x > last) {
                alpha = 0.0;
            } else if (x <= first) {
                alpha = 1.0;
            } else {
                alpha = (last - x) / static_cast<float>(FadeWidthPixel);
            }
            surface->setAlpha(alpha * base_alpha_);
            x += surface->rect().w;
        }
    }


    void draw(const Rect<long>* src, const Rect<long>* dest)
    {
        if (! text_.isValid()) {
            return;
        }
        Rect<long> sub_dest(*dest);
        sub_dest.y += rubi_pixel_size_;
        text_.draw(src, &sub_dest);

        sub_dest.y -= rubi_pixel_size_;
        int index = 0;
        for (Surfaces::iterator it = rubi_text_.begin();
             it != rubi_text_.end(); ++it, ++index) {
            Surface* surface = *it;
            sub_dest.w = surface->rect().w;
            sub_dest.h = surface->rect().h;
            sub_dest.x = dest->x + rubi_x_[index];
            surface->draw(src, &sub_dest);
        }
    }
};


TextRubiFadeSurface::TextRubiFadeSurface(const Font& font, const char* text,
                                         const Font& rubi_font,
                                         const char* kana_only_text)
    : pimpl(new pImpl(font, text, rubi_font, kana_only_text))
{
}


TextRubiFadeSurface::~TextRubiFadeSurface(void)
{
}


bool TextRubiFadeSurface::isValid(void) const
{
    // ルビは表示されなくても valid だとみなす
    return pimpl->text_.isValid();
}


Rect<long> TextRubiFadeSurface::rect(void) const
{
    return pimpl->rect_;
}


void TextRubiFadeSurface::setAlpha(float alpha)
{
    pimpl->base_alpha_ = alpha;
    pimpl->setAlpha();
}


float TextRubiFadeSurface::alpha(void) const
{
    return pimpl->base_alpha_;
}


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


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


void TextRubiFadeSurface::setFadePercent(size_t percent)
{
    pimpl->percent_ = min(percent, static_cast<size_t>(100));
    pimpl->setAlpha();
}
