/*
*  qm_Scroller.ccp
*  QUIMUP graphical text scroller
*  © 2008-2024 Johan Spee
*  SPDX-License-Identifier: GPL-3.0-or-later
*/

#include "qm_scroller.h"
#include <QPaintEvent>
#include <QPainter>


qm_Scroller::qm_Scroller(QWidget *parent)
{
    // defaults etc.
    s_artist_keep = "";
    s_title_keep = "";
    QLabel::setParent(parent);
    steptime = 60;  // msec
    scrollstep_size = 1;
    scrollpos = -scrollstep_size;
    b_step_busy = false;
    b_pause = false;
    b_fast = false;
    b_scrolling = false;
    b_init_palette = true;
    b_init_font = true;
    W_display = 320;
    H_display = 24;
    info_font = font();
    title_font = info_font;
    fg_color = this->palette().color(QPalette::WindowText);
    bg_color = this->palette().color(QPalette::Window);
    steploop = new QTimer(this);
    connect( steploop, SIGNAL(timeout()), this, SLOT(do_scrollstep()) );
}

// called from player (320, 24)
void qm_Scroller::setFixedSize(int W, int H)
{
    QLabel::setFixedSize(W, H); // Apply here
    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    W_display = W;
    H_display = H;
}


void qm_Scroller::setFont(int size, bool bold, bool italic)
{
    // size, bold, italic set in qm_Player::set_fonts()
    QFont font;
    font.setPointSize(size);
    if (bold)
        font.setWeight(QFont::DemiBold);

    info_font = font;

    title_font = font;
    if (italic)
          title_font.setItalic(true);

    // re-render when scrolling
    if (b_scrolling)
    {
        // reset
        stop_scroll();
        scrollpos = -scrollstep_size;
        b_scrolling = false;
    }

    if (b_init_font)
        b_init_font = false;
    else
        render_info(s_artist_keep, s_title_keep);
}


void qm_Scroller::setPalette(QPalette pal)
{
    bg_color = pal.color(QPalette::Window);
    fg_color = pal.color(QPalette::WindowText);

    if (b_scrolling)
    {
        // reset
        stop_scroll();
        scrollpos = -scrollstep_size;
        b_scrolling = false;
    }

    if (b_init_palette)
        b_init_palette = false;
    else
        render_info(s_artist_keep, s_title_keep);
}


void qm_Scroller::mousePressEvent(QMouseEvent *)
{
    pause(true);
}


void qm_Scroller::mouseReleaseEvent(QMouseEvent *)
{
    pause(false);
}


void qm_Scroller::enterEvent (QEnterEvent *)
{
    if (!b_scrolling || b_pause)
        return;
    b_fast = true;
    start_scroll();
}


void qm_Scroller::leaveEvent (QEvent *)
{
    if (!b_scrolling || b_pause)
        return;
    b_fast = false;
    start_scroll();
}

// triggered by 'repaint()'
void qm_Scroller::paintEvent(QPaintEvent *)
{
    QPainter painter;
    painter.begin(this);
    const QRect rect = QRect(0, 0, W_display , H_display);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    painter.drawPixmap(rect, px_toshow);
    painter.end();
}


void qm_Scroller::render_info(QString artist, QString title)
{
    QChar qc = QChar(0x25B8); // 0x2022 bullet, 0x25B6 arrow,  0x25B8 small arrow
    QString s_dot = QString("  %1  ").arg(qc);
    QString s_sizer = QString();
    bool b_artist;
    bool b_title;

    // do first (steploop problems when done last)
     if (b_scrolling)
    {
        stop_scroll();
        scrollpos = -scrollstep_size;
        b_scrolling = false;
        W_string = 0;
    }

    if (title.isNull() || title.isEmpty())
    {
       b_title = false;
       s_title_keep = QString();
    }
    else
    {
       b_title = true;
       s_title_keep = title;
       s_sizer.append(title); // for H_string and Y_offset
    }

    if (artist.isNull() || artist.isEmpty())
    {
        b_artist = false;
        s_artist_keep = QString();
        if (b_title)
        {
            // only title
            title.prepend(" ");
            title.append (" ");
        }
    }
    else
    {
        b_artist = true;
        s_artist_keep = artist;
        if (b_title)
        {
            // artist and title
            artist.prepend(" ");
            artist.append(" : ");
            title.append(" ");
        }
        else
        {
            // only artist
            artist.prepend(" ");
            artist.append(" ");
        }

        s_sizer.append(artist); // for H_string and Y_offset
    }

    if (s_sizer.isNull())
        s_sizer = "BBQ"; // high and low

    // get H and Y from s_sizer
    lb_render.setFont(info_font);
    lb_render.setText(s_sizer);
    int H_string = (lb_render.minimumSizeHint()).height();
    int Y_offset = (H_display - H_string)/2;

    int W_dot = 0;
    int W_artist = 0;
    int W_title = 0;
    W_string = 0;

    lb_render.setText(s_dot);
    W_dot = (lb_render.minimumSizeHint()).width();

    if (b_artist)
    {
        lb_render.setText(artist);
        W_artist = (lb_render.minimumSizeHint()).width();
        W_string += W_artist;
    }

    if (b_title)
    {
        lb_render.setFont(title_font);
        lb_render.setText(title);
        W_title = (lb_render.minimumSizeHint()).width();
        W_string += W_title;
    }

    if (!b_artist && !b_title) // show s_dot >
        W_string = W_dot;

    int X_offset = (W_display - W_string)/2;

    QRect rect;
    px_toshow = QPixmap(W_display, H_display);
    px_toshow.fill(bg_color);

    if (W_string < W_display)
    {
        int xoff = X_offset;
        QPainter scroll_painter(&px_toshow);
        scroll_painter.setFont(info_font);
        scroll_painter.setPen(fg_color);

        if (b_artist)
        {
            rect.setRect(xoff, Y_offset, W_artist , H_string);
            scroll_painter.drawText(rect, Qt::AlignLeft, artist);
            xoff += W_artist;
        }

        if (b_title)
        {
           scroll_painter.setFont(title_font);
           rect.setRect(xoff, Y_offset, W_title , H_string);
           scroll_painter.drawText(rect, Qt::AlignLeft, title);
           scroll_painter.setFont(info_font);
           // done
        }

        if (!b_artist && !b_title) // show s_dot
        {
            rect.setRect(xoff, Y_offset, W_dot , H_string);
            scroll_painter.drawText(rect, Qt::AlignLeft, s_dot);
        }

        repaint();
        return;
    }

    // else we must scroll

    int xoff = 0;
    // we append s_dot here
    W_string += W_dot;
    px_scroller = QPixmap(2*W_string, H_display);
    px_scroller.fill(bg_color);

    QPainter scroll_painter(&px_scroller);
    scroll_painter.setFont(info_font);
    scroll_painter.setPen(fg_color);

    // twice: scroller must be able to read beyond the end of W_string
    int count = 1;
    while (count < 3)
    {
        count++;

        if (b_artist)
        {
            rect.setRect(xoff, Y_offset, W_artist , H_string);
            scroll_painter.drawText(rect, Qt::AlignLeft, artist);
            xoff += W_artist;
        }

        if (b_title)
        {
            scroll_painter.setFont(title_font);
            rect.setRect(xoff, Y_offset, W_title , H_string);
            scroll_painter.drawText(rect, Qt::AlignLeft, title);
            scroll_painter.setFont(info_font);
            xoff += W_title;
        }

        rect.setRect(xoff, Y_offset, W_dot , H_string);
        scroll_painter.drawText(rect, Qt::AlignLeft, s_dot);
        xoff += W_dot;
    }

    start_scroll();
}


void qm_Scroller::start_scroll()
{
    if (steploop->isActive())
        stop_scroll();

    int delay = steptime;
    if (b_fast)
        delay = 10;
    b_scrolling = true;
    b_pause = false;
    steploop->start(delay);
}


void qm_Scroller:: stop_scroll ()
{
    if (steploop->isActive())
        steploop->stop();
//  wait for step to finish
    while (b_step_busy)
    {
        usleep(200);
    }
}


void qm_Scroller::do_scrollstep()
{
    if (b_pause || b_step_busy || !b_scrolling)
        return;

    b_step_busy = true;

    scrollpos += scrollstep_size;

    if (scrollpos >= W_string)
        scrollpos -= W_string;

    QRect grab = QRect(scrollpos, 0, W_display, H_display);
    px_toshow = px_scroller.copy(grab);

    // show the result
    repaint();
    b_step_busy = false;
}


void qm_Scroller::pause(bool p)
{
    b_pause = p;
}


qm_Scroller::~qm_Scroller()
{}
