/*
    TikZiT - a GUI diagram editor for TikZ
    Copyright (C) 2018 Aleks Kissinger

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#include "style.h"
#include "tikzit.h"

Style *noneStyle = new Style("none", new GraphElementData());
Style *unknownStyle = new Style("unknown", new GraphElementData({GraphElementProperty("tikzit fill", "blue")}));
Style *noneEdgeStyle = new Style("none", new GraphElementData({GraphElementProperty("-")}));

Style::Style() : _name("none")
{
    _data = new GraphElementData(this);
}

Style::Style(QString name, GraphElementData *data) : _name(name), _data(data)
{
    _data->setParent(this);
}

bool Style::isNone() const
{
    return _name == "none";
}

GraphElementData *Style::data() const
{
    return _data;
}

QString Style::name() const
{
    return _name;
}

QColor Style::strokeColor(bool tikzitOverride) const
{
    QString col = propertyWithDefault("draw", "black", tikzitOverride);
    return tikzit->colorByName(col);
}

QColor Style::fillColor(bool tikzitOverride) const
{
    QString col = propertyWithDefault("fill", "white", tikzitOverride);
    return tikzit->colorByName(col);
}

QBrush Style::brush() const
{
    if (hasFill()) {
        return QBrush(fillColor());
    } else {
        return Qt::NoBrush;
    }
}

bool Style::hasFill() const
{
    return (propertyWithDefault("fill", "none") != "none");
}

bool Style::hasStroke() const
{
    if (isEdgeStyle()) return propertyWithDefault("draw", "black") != "none";
    else return (propertyWithDefault("draw", "none") != "none");
}

QString Style::shape(bool tikzitOverride) const
{
    return propertyWithDefault("shape", "circle", tikzitOverride);
}


// TODO
int Style::strokeThickness() const
{
    return 1;
}

bool Style::isEdgeStyle() const
{
    if (_data->atom("-")  || _data->atom("->") || _data->atom("-|") ||
        _data->atom("<-") || _data->atom("<->") || _data->atom("<-|") ||
        _data->atom("|-") || _data->atom("|->") || _data->atom("|-|")) return true;
    else return false;
}



QString Style::propertyWithDefault(QString prop, QString def, bool tikzitOverride) const
{
    if (_data == 0) return def;
    QString val;
    if (tikzitOverride) {
        val = _data->property("tikzit " + prop);
        if (val.isNull()) val = _data->property(prop);
    } else {
        val = _data->property(prop);
    }
    if (val.isNull()) val = def;
    return val;
}

QString Style::tikz() const
{
    return "\\tikzstyle{" + _name + "}=" + _data->tikz();
}

void Style::setArrowAtom(QString atom)
{
    _data->unsetAtom("-");
    _data->unsetAtom("->");
    _data->unsetAtom("-|");

    _data->unsetAtom("<-");
    _data->unsetAtom("<->");
    _data->unsetAtom("<-|");

    _data->unsetAtom("|-");
    _data->unsetAtom("|->");
    _data->unsetAtom("|-|");

    _data->setAtom(atom);
}

void Style::setName(const QString &name)
{
    _name = name;
}

Style::ArrowTipStyle Style::arrowHead() const
{
    if (_data->atom("->") || _data->atom("<->") || _data->atom("|->")) return Pointer;
    if (_data->atom("-|") || _data->atom("<-|") || _data->atom("|-|")) return Flat;
    return NoTip;
}

Style::ArrowTipStyle Style::arrowTail() const
{
    if (_data->atom("<-") || _data->atom("<->") || _data->atom("<-|")) return Pointer;
    if (_data->atom("|-") || _data->atom("|->") || _data->atom("|-|")) return Flat;
    return NoTip;
}

Style::DrawStyle Style::drawStyle() const
{
    if (_data->atom("dashed")) return Dashed;
    if (_data->atom("dotted")) return Dotted;
    return Solid;
}


QPen Style::pen() const
{
    if (hasStroke()) {
        QPen p(strokeColor());
        p.setWidthF((float)strokeThickness() * 2.0f);

        QVector<qreal> pat;
        switch (drawStyle()) {
        case Dashed:
            pat << 3.0 << 3.0;
            p.setDashPattern(pat);
            break;
        case Dotted:
            pat << 1.0 << 1.0;
            p.setDashPattern(pat);
            break;
        case Solid:
            break;
        }

        return p;
    } else {
        return Qt::NoPen;
    }
}

QPainterPath Style::path() const
{
    QPainterPath pth;
    QString sh = shape();

    if (sh == "rectangle") {
        pth.addRect(-30.0f, -30.0f, 60.0f, 60.0f);
    } else { // default is 'circle'
        pth.addEllipse(QPointF(0.0f,0.0f), 30.0f, 30.0f);
    }
    return pth;
}

QIcon Style::icon() const
{
    if (!isEdgeStyle()) {
        // draw an icon matching the style
        QImage px(100,100,QImage::Format_ARGB32_Premultiplied);
        px.fill(Qt::transparent);


        QPainter painter(&px);
        painter.setRenderHint(QPainter::Antialiasing);
        QPainterPath pth = path();
        pth.translate(50.0f, 50.0f);

        if (isNone()) {
            QColor c(180,180,200);
            painter.setPen(QPen(c));
            painter.setBrush(QBrush(c));
            painter.drawEllipse(QPointF(50.0f,50.0f), 3,3);

            QPen pen(QColor(180,180,220));
            pen.setWidth(3);
            QVector<qreal> p;
            p << 2.0 << 2.0;
            pen.setDashPattern(p);
            painter.setPen(pen);
            painter.setBrush(Qt::NoBrush);
            painter.drawPath(pth);
        } else {
            painter.setPen(pen());
            painter.setBrush(brush());
            painter.drawPath(pth);
        }

        return QIcon(QPixmap::fromImage(px));
    } else {
        // draw an icon matching the style
        QPixmap px(100,100);
        px.fill(Qt::transparent);
        QPainter painter(&px);

//        if (_data == 0) {
//            QPen pen(Qt::black);
//            pen.setWidth(3);
//        } else {
//            painter.setPen(pen());
//        }

        QPen pn = pen();
        painter.setPen(pn);

        if (hasFill()) {
            painter.fillRect(10,50,80,30,brush());
        }

        painter.drawLine(10, 50, 90, 50);

        pn.setStyle(Qt::SolidLine);
        painter.setPen(pn);



        switch (arrowHead()) {
        case Pointer:
            painter.drawLine(90,50,80,40);
            painter.drawLine(90,50,80,60);
            break;
        case Flat:
            painter.drawLine(90,40,90,60);
            break;
        case NoTip:
            break;
        }

        switch (arrowTail()) {
        case Pointer:
            painter.drawLine(10,50,20,40);
            painter.drawLine(10,50,20,60);
            break;
        case Flat:
            painter.drawLine(10,40,10,60);
            break;
        case NoTip:
            break;
        }


        return QIcon(px);
    }
}

QString Style::category() const
{
    return propertyWithDefault("tikzit category", "", false);
}
