#include "etext.h"
#include "etextattr.h"
#include "etextinput.h"

eText::eText(InteractiveType type, QGraphicsItem *parent) :
    eObject(QRectF(0, 0, 120, 100), type, parent),
    m_wAttr(nullptr),
    m_wTextInput(nullptr)
{
    // Widget
    m_attr.text = tr("Hello Text !");
    m_attr.opt.setAlignment(Qt::AlignCenter);
    m_attr.opt.setWrapMode(QTextOption::WrapAnywhere);
    m_attr.cText       = Qt::red;
    m_attr.cTextShadow = QColor(0,0,0,0);
    m_attr.cBackground = QColor(0,0,0,0);
    m_attr.lineSpacing = 0;
    //Play
    m_attr.playStyle         = Static;
    m_attr.headTailConnected = false;
    m_attr.headTailSpacing   = 0;
    m_attr.rollingSpeed      = 0;
    m_attr.rollingStyle      = Left2Right;
    m_attr.playDuration      = 0;
}

eText::eText(const QJsonObject &json, InteractiveType type, QGraphicsItem *parent) :
    eObject(json["geometry"].toObject(), type, parent),
    m_wAttr(nullptr),
    m_wTextInput(nullptr)
{
    QJsonDocument jRoot;
    jRoot.setObject(json);
    // Widget
    m_attr.text =                                             jRoot["widget"]["text"]                 .toString();
    m_attr.font.setFamily(                                    jRoot["widget"]["font"]["family"]       .toString());
    m_attr.font.setPointSize(                                 jRoot["widget"]["font"]["size"]         .toInt());
    m_attr.font.setBold(                                      jRoot["widget"]["font"]["bold"]         .toBool());
    m_attr.font.setItalic(                                    jRoot["widget"]["font"]["italic"]       .toBool());
    m_attr.font.setUnderline(                                 jRoot["widget"]["font"]["underline"]    .toBool());
    m_attr.font.setLetterSpacing(QFont::AbsoluteSpacing,      jRoot["widget"]["font"]["letterSpacing"].toInt());
    m_attr.opt.setAlignment(static_cast<Qt::Alignment>(       jRoot["widget"]["align"]                .toInt()));
    m_attr.cText       = LoAppTools::getInstance()->int2Color(jRoot["widget"]["color"]["text"]        .toInt());
    m_attr.cTextShadow = LoAppTools::getInstance()->int2Color(jRoot["widget"]["color"]["shadow"]      .toInt());
    m_attr.cBackground = LoAppTools::getInstance()->int2Color(jRoot["widget"]["color"]["background"]  .toInt());
    m_attr.lineSpacing =                                      jRoot["widget"]["lineSpacing"]          .toInt();
    // Play
    m_attr.playStyle         = jRoot["play"]["style"]            .toInt();
    m_attr.headTailConnected = jRoot["play"]["headTailConnected"].toBool();
    m_attr.headTailSpacing   = jRoot["play"]["headTailSpacing"]  .toInt();
    m_attr.rollingSpeed      = jRoot["play"]["rollingSpeed"]     .toInt();
    m_attr.rollingStyle      = jRoot["play"]["rollingStyle"]     .toInt();
    m_attr.playDuration      = jRoot["play"]["duration"]         .toInt();
}

QWidget* eText::wAttr()
{
    QWidget *wObj = eObject::wAttr();
    QWidget *w = wAttrElement();
    static_cast<QBoxLayout*>(w->layout())->insertWidget(0, wObj);
    return w;
}

QWidget* eText::wAttrElement()
{
    eTextAttr *w = new eTextAttr(m_attr);
    connect(w, SIGNAL(destroyed(QObject*)), this, SLOT(onWAttrClosed()));
    // Widget
    connect(w, SIGNAL(sFontFamilyChanged(const QString&)),     this, SLOT(onFontFamilyChanged(const QString&)));
    connect(w, SIGNAL(sFontSizeChanged(int)),                  this, SLOT(onFontSizeChanged(int)));
    connect(w, SIGNAL(sFontBoldChanged(bool)),                 this, SLOT(onFontBoldChanged(bool)));
    connect(w, SIGNAL(sFontItalicsChanged(bool)),              this, SLOT(onFontItalicsChanged(bool)));
    connect(w, SIGNAL(sFontUnderlineChanged(bool)),            this, SLOT(onFontUnderlineChanged(bool)));
    connect(w, SIGNAL(sTextHAlignChanged(int)),                this, SLOT(onTextHAlignChanged(int)));
    connect(w, SIGNAL(sTextVAlignChanged(int)),                this, SLOT(onTextVAlignChanged(int)));
    connect(w, SIGNAL(sTextColorChanged(const QColor&)),       this, SLOT(onTextColorChanged(const QColor&)));
    connect(w, SIGNAL(sTextShadowColorChanged(const QColor&)), this, SLOT(onTextShadowColorChanged(const QColor&)));
    connect(w, SIGNAL(sBackgroundColorChanged(const QColor&)), this, SLOT(onBackgroundColorChanged(const QColor&)));
    connect(w, SIGNAL(sTextLetterSpacingChanged(int)),         this, SLOT(onTextLetterSpacingChanged(int)));
    connect(w, SIGNAL(sTextLineSpacingChanged(int)),           this, SLOT(onTextLineSpacingChanged(int)));
    // Play
    connect(w, SIGNAL(sPlayStyleChanged(int)),       this, SLOT(onPlayStyleChanged(int)));
    connect(w, SIGNAL(sHeadTailConnected(bool)),     this, SLOT(onHeadTailConnected(bool)));
    connect(w, SIGNAL(sHeadTailSpacingChanged(int)), this, SLOT(onHeadTailSpacingChanged(int)));
    connect(w, SIGNAL(sRollingSpeedChanged(int)),    this, SLOT(onRollingSpeedChanged(int)));
    connect(w, SIGNAL(sRollingStyleChanged(int)),    this, SLOT(onRollingStyleChanged(int)));
    connect(w, SIGNAL(sPlayDurationChanged(int)),    this, SLOT(onPlayDurationChanged(int)));
    m_wAttr = w;
    return w;
}

QJsonObject eText::elementJson() const
{
    QJsonObject oRoot;
    QJsonObject oWidget;
    QJsonObject oColor;
    QJsonObject oFont;
    QJsonObject oPlay;
    // Interior
    oRoot["elementType"]   = "Text";
    oRoot["elementTypeId"] = type();
    oRoot["geometry"]      = eObject::elementJson();
    // Widget
    oWidget["text"]        = m_attr.text;
    oFont["family"]        = m_attr.font.family();
    oFont["size"]          = m_attr.font.pointSize();
    oFont["bold"]          = m_attr.font.bold();
    oFont["italic"]        = m_attr.font.italic();
    oFont["underline"]     = m_attr.font.underline();
    oFont["letterSpacing"] = m_attr.font.letterSpacing();
    oWidget["font"]        = oFont;
    oWidget["align"]       = static_cast<int>(m_attr.opt.alignment());
    oColor["text"]         = LoAppTools::getInstance()->color2Int(m_attr.cText);
    oColor["shadow"]       = LoAppTools::getInstance()->color2Int(m_attr.cTextShadow);
    oColor["background"]   = LoAppTools::getInstance()->color2Int(m_attr.cBackground);
    oWidget["color"]       = oColor;
    oWidget["lineSpacing"] = m_attr.lineSpacing;
    oRoot["widget"]        = oWidget;
    // Play
    oPlay["style"]             = m_attr.playStyle;
    oPlay["headTailConnected"] = m_attr.headTailConnected;
    oPlay["headTailSpacing"]   = m_attr.headTailSpacing;
    oPlay["rollingSpeed"]      = m_attr.rollingSpeed;
    oPlay["rollingStyle"]      = m_attr.rollingStyle;
    oPlay["duration"]          = m_attr.playDuration;
    oRoot["play"]              = oPlay;
    return oRoot;
}

void eText::setTextContents(QTextDocument &doc)
{
    const int lineSpacing = QFontMetrics(m_attr.font).lineSpacing();
    m_lineH = m_attr.lineSpacing + lineSpacing;

    QString ctx = QString("<style>p{"
                          "color:rgba(%1,%2,%3,%4);"
                          "line-height:%5px;"
                          "white-space:pre-wrap;"
                          "}</style>"
                          "<p>%6</p>")
                          .arg(m_attr.cText.red()).arg(m_attr.cText.green())
                          .arg(m_attr.cText.blue()).arg(m_attr.cText.alpha())
                          .arg(m_lineH)
                          .arg(m_attr.text);
    doc.setHtml(ctx);
}

void eText::setTextVAlign(int align,  QTextDocument &doc)
{
    qreal ls, ofs_h, ofs_v;
    qreal painter_x, painter_y;
    qreal clip_x, clip_y, clip_w, clip_h;
    QRectF r = rect();
    QSizeF s = doc.size();
    align &= Qt::AlignVertical_Mask;

    if(s.height() > r.height()) {
        int num = static_cast<int>(r.height()) / m_lineH;
        ofs_h  = r.height() - m_lineH * num;
        clip_x = r.x();
        clip_y = r.y();
        clip_w = r.width();
        clip_h = num ? m_lineH * num : 0.000001;
        r      = QRectF(clip_x, clip_y, clip_w, clip_h);
        ls     = rect().height() - clip_h + QFontMetrics(m_attr.font).leading();
    } else {
        ls     = QFontMetrics(m_attr.font).leading() + m_attr.lineSpacing;
    }

    clip_x = 0;
    clip_y = 0;
    clip_w = r.width();
    clip_h = (s.height() < r.height()) ? s.height() : r.height();

    painter_x = r.x();
    switch (align) {
    case Qt::AlignTop:
        ofs_v = 0;
        painter_y = 0;
        break;
    case Qt::AlignVCenter:
        ofs_v = (r.height() - s.height()) / 2;
        painter_y = (s.height() < r.height()) ? r.y() + ofs_v : 0;
        painter_y += ls / 2;
        break;
    case Qt::AlignBottom:
        ofs_v = r.height() - s.height();
        painter_y = (s.height() < r.height()) ? r.y() + ofs_v : 0;
        painter_y += ls;
        break;
    default:
        return;
    }

    m_pText = QPointF(painter_x, painter_y);
    m_rClip = QRectF(clip_x, clip_y, clip_w, clip_h);
}

void eText::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->save();

    QBrush bshBackground = LoAppTools::getInstance()->getBrush(m_attr.cBackground);
    if(bshBackground != Qt::NoBrush) {
#if 1
        painter->fillRect(rect(), bshBackground);
#else
        QRectF r = rect();
        qreal x, y, w, h;
        x = r.x() - 1;
        y = r.y() - 1;
        w = r.width() + 2;
        h = r.height() + 2;
        r = QRectF(x, y, w, h);
        painter->fillRect(r, bshBackground);
#endif
    }

    QBrush bshTextShadow = LoAppTools::getInstance()->getBrush(m_attr.cTextShadow);
    if(bshTextShadow != Qt::NoBrush) {
        painter->setBackgroundMode(Qt::OpaqueMode);
        painter->setBackground(bshTextShadow);
    }
#if 0
    painter->setPen(m_attr.pen);
    painter->setFont(m_attr.font);
    painter->drawText(rect(), m_attr.text, m_attr.opt);
#else
    QTextDocument doc;
    doc.setDefaultFont(m_attr.font);
    doc.setDefaultTextOption(m_attr.opt);
    doc.setDocumentMargin(0);
    doc.setTextWidth(rect().width());
    setTextContents(doc);
    setTextVAlign(m_attr.opt.alignment(), doc);
    painter->translate(m_pText);
    doc.drawContents(painter, m_rClip);
//    qDebug() << "Block Count:" << doc.blockCount();
#endif

    painter->restore();
    LoQGraphicsObject::paint(painter, option, widget);
}

void eText::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    if(Qt::LeftButton == event->button()) {
        setInput();
    }
}

void eText::setInput()
{
    if(nullptr == m_wTextInput && nullptr != m_wAttr) {
        m_wTextInput = new eTextInput(m_attr.text, m_wAttr);
        connect(m_wTextInput, SIGNAL(sTextChanged(const QString &)), this, SLOT(onTextChanged(const QString &)));
        connect(m_wTextInput, SIGNAL(destroyed(QObject*)),           this, SLOT(onInputClosed()));
        m_wTextInput->show();
    }
}

void eText::onTextHAlignChanged(int align)
{
    int res = m_attr.opt.alignment();
    res &= ~Qt::AlignHorizontal_Mask;
    res |= align;
    m_attr.opt.setAlignment(static_cast<Qt::Alignment>(res));
    updateGeometry();
}

void eText::onTextVAlignChanged(int align)
{
    int res = m_attr.opt.alignment();
    res &= ~Qt::AlignVertical_Mask;
    res |= align;
    m_attr.opt.setAlignment(static_cast<Qt::Alignment>(res));
    updateGeometry();
}
