#include <QDebug>
#include <QGraphicsScene>
#include <QRegExp>

#include "headingobj.h"

extern bool debug;

/////////////////////////////////////////////////////////////////
// HeadingObj
/////////////////////////////////////////////////////////////////
HeadingObj::HeadingObj(QGraphicsItem *parent) : MapObj(parent)
{
    // qDebug() << "Const HeadingObj (s) ";
    init();
}

HeadingObj::~HeadingObj()
{
    //  qDebug() << "Destr. HeadingObj "<<heading;
    while (!textline.isEmpty())
        delete textline.takeFirst();
}

void HeadingObj::init()
{
    textwidth = 40;
    color = QColor("black");
    font = QFont();
    heading = "";
    angle = 0;
}

void HeadingObj::copy(HeadingObj *other)
{
    MapObj::copy(other);
    textwidth = other->textwidth;
    color = other->color;
    font = other->font;
    setText(other->text());
}

void HeadingObj::move(double x, double y)
{
    MapObj::move(x, y);

    qreal h;  // height of a textline
    qreal ho; // offset of height while drawing all lines

    if (!textline.isEmpty())
        h = textline.first()->boundingRect().height();
    else
        h = 2;
    ho = 0;
    for (int i = 0; i < textline.size(); ++i) {
        textline.at(i)->setPos(x, y + ho);
        ho = ho + h;
    }
}

void HeadingObj::moveBy(double x, double y)
{
    move(x + absPos.x(), y + absPos.y());
}

void HeadingObj::positionBBox()
{
    bbox.setX(absPos.x());
    bbox.setY(absPos.y());
}

void HeadingObj::calcBBoxSize()
{
    qreal w = 0;
    qreal h = 0;
    // Using Backspace an empty heading might easily be created, then there
    // would be textline.first()==NULL This can be worked around by the
    // following, but then no selection would be visible, thus we prevent it in
    // ::setText()
    if (!textline.isEmpty()) {
        for (int i = 0; i < textline.size(); i++) {
            h += textline.at(i)->boundingRect().height();
            if (w < textline.at(i)->boundingRect().width())
                w = textline.at(i)->boundingRect().width();
        }
    }
    bbox.setSize(QSizeF(w, h));
}

QGraphicsTextItem *HeadingObj::newLine(QString s)
{
    QGraphicsTextItem *t = new QGraphicsTextItem(s, parentItem());
    t->setFont(font);
    t->setZValue(dZ_TEXT);
    t->setDefaultTextColor(color);
    t->setRotation(angle);
    return t;
}

void HeadingObj::setTransformOriginPoint(const QPointF &p)
{
    for (int i = 0; i < textline.size(); i++) {
        textline.at(i)->setTransformOriginPoint(p);
    }
}

void HeadingObj::setRotation(const qreal &a)
{
    angle = a;
    for (int i = 0; i < textline.size(); i++)
        textline.at(i)->setRotation(angle);
}

qreal HeadingObj::getRotation() { return angle; }

void HeadingObj::setText(QString s)
{
    heading = s;

    // remove old textlines and prepare generating new ones
    while (!textline.isEmpty())
        delete textline.takeFirst();

    if (s.startsWith("<html>") ||
        s.startsWith("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" "
                     "\"http://www.w3.org/TR/REC-html40/strict.dtd\">")) {
        QGraphicsTextItem *t = new QGraphicsTextItem();
        t->setFont(font);
        t->setZValue(dZ_TEXT);
        t->setHtml(s);
        t->setDefaultTextColor(color);
        t->setRotation(angle);
        scene()->addItem(t);
        textline.append(t);
    }
    else {
        // prevent empty textline, so at least a small selection stays
        // visible for this heading
        if (s.length() == 0)
            s = "  ";

        int i = 0;  // index for actual search for ws
        int j = 0;  // index of last ws
        int k = 0;  // index of "<br>" or similar linebreak
        int br = 0; // width of found break, e.g. for <br> it is 4
        QRegExp re("<br.*/>");
        re.setMinimal(true);

        // set the text and wrap lines
        while (s.length() > 0) {
            // ok, some people wanted manual linebreaks, here we go
            k = re.indexIn(s, i);
            if (k >= 0) {
                br = re.cap(0).length();
                i = k;
            }
            else
                i = s.indexOf(" ", i);
            if (i < 0 && j == 0) { // no ws found at all in s
                // append whole s
                textline.append(newLine(s));
                s = "";
            }
            else {
                if (i < 0 && j > 0) { // no ws found in actual search
                    if (s.length() <= textwidth) {
                        textline.append(newLine(s));
                        s = "";
                    }
                    else {
                        textline.append(newLine(s.left(j)));
                        s = s.mid(j + 1, s.length());
                        j = 0;
                    }
                }
                else {
                    if (i >= 0 &&
                        i <= static_cast<int>(
                                 textwidth)) { // there is a ws in textwidth
                        if (br > 0) {
                            // here is a linebreak
                            textline.append(newLine(s.left(i)));
                            s = s.mid(i + br, s.length());
                            i = 0;
                            j = 0;
                            br = 0;
                        }
                        else {
                            j = i;
                            i++;
                        }
                    }
                    else {
                        if (i > static_cast<int>(textwidth)) {
                            if (j > 0) { // a ws out of textwidth, but we have
                                         // also one in
                                textline.append(newLine(s.left(j)));
                                s = s.mid(j + 1, s.length());
                                i = 0;
                                j = 0;
                            }
                            else { // a ws out of text, but none in
                                textline.append(newLine(s.left(i)));
                                s = s.mid(i + 1, s.length());
                                i = 0;
                            }
                        }
                    }
                }
            }
        }
    } // ASCII heading with multiple lines
    setVisibility(visible);
    move(absPos.x(), absPos.y());
    calcBBoxSize();
}

QString HeadingObj::text() { return heading; }

void HeadingObj::setFont(QFont f)
{
    if (font != f) {
        font = f;
        setText(text());
    }
}

QFont HeadingObj::getFont() { return font; }

void HeadingObj::setColor(QColor c)
{
    if (color != c) {
        color = c;
        for (int i = 0; i < textline.size(); ++i)
            // TextItem
            textline.at(i)->setDefaultTextColor(c);
        // SimpleTextItem
        // textline.at(i)->setBrush(c);
    }
}

QColor HeadingObj::getColor() { return color; }

void HeadingObj::setZValue(double z)
{
    for (int i = 0; i < textline.size(); ++i)
        textline.at(i)->setZValue(z);
}

void HeadingObj::setVisibility(bool v)
{
    MapObj::setVisibility(v);
    for (int i = 0; i < textline.size(); ++i)
        if (v)
            textline.at(i)->show();
        else
            textline.at(i)->hide();
}

qreal HeadingObj::getHeight() { return bbox.height(); }

qreal HeadingObj::getWidth() { return bbox.width(); }
