#include "xml-freemind.h"

#include <QDebug>
#include <QMessageBox>

#include "branchitem.h"
#include "misc.h"
#include "vymmodel.h"

extern Settings settings;
extern QString vymVersion;

bool parseFreemindHandler::nodeLikeState() 
{
    if (state == StateCenter || state == StateMainNode || state == StateNode)
        return true;
    else
        return false;
}

bool parseFreemindHandler::startDocument() // FIXME-3 import not complete yet
{
    errorProt = "";
    state = StateInit;
    stateStack.clear();
    stateStack.append(StateInit);
    isVymPart = false;
    return true;
}

QString parseFreemindHandler::parseHREF(QString href)
{
    QString type = href.section(":", 0, 0);
    QString path = href.section(":", 1, 1);
    if (!tmpDir.endsWith("/"))
        return tmpDir + "/" + path;
    else
        return tmpDir + path;
}

bool parseFreemindHandler::startElement(const QString &, const QString &,
                                        const QString &eName,
                                        const QXmlAttributes &atts)
{
    QColor col;
    /* Testing
    if (eName.contains("node"))
    qDebug() << "startElement: <" << eName
             << ">     state=" << state
             << "  laststate=" << stateStack.last();
             //<< "   loadMode=" << loadMode
             //<<"       line=" << QXmlDefaultHandler::lineNumber();
    */

    stateStack.append(state);
    if (state == StateInit && (eName == "map")) {
        state = StateMap;
        if (!atts.value("version").isEmpty()) {
            QString v = "0.9.0";
            if (!versionLowerOrEqual(atts.value("version"), v))
                QMessageBox::warning(
                    0, "Warning: Version Problem",
                    "<h3>Freemind map is newer than version " + v +
                        " </h3>"
                        "<p>The map you are just trying to load was "
                        "saved using freemind " +
                        atts.value("version") +
                        ". "
                        "Your version of vym can parse freemind " +
                        v + ".");
        }
        // Create mapcenter
        model->clear();
        mapCenter = model->createMapCenter();
        lastBranch = mapCenter;

        // Create two hidden branches, because Freemind has no relative
        // positioning for mainbranches
        mainBranchLeft = model->createBranch(lastBranch);
        mainBranchRight = model->createBranch(lastBranch);

        mainBranchLeft->setRelPos(QPointF(-200, 0));
        mainBranchLeft->setHeadingPlainText(" ");
        model->emitDataChanged(mainBranchLeft);

        mainBranchRight->setRelPos(QPointF(200, 0));
        mainBranchRight->setHeadingPlainText(" ");
        model->emitDataChanged(mainBranchRight);
    }
    else if (eName == "attribute_registry" && state == StateMap) {
        state = StateAttributeRegistry;
    }
    else if (eName == "attribute_name" && state == StateAttributeRegistry) {
        state = StateAttributeName;
    }
    else if (eName == "attribute_value" && state == StateAttributeName) {
        state = StateAttributeValue;
    }
    else if (eName == "node" && state == StateMap) {
        state = StateCenter;
        lastBranch = mapCenter;
        readNodeAttr(atts);
    }
    else if (eName == "node" && state == StateCenter) {
        state = StateMainNode;
        lastBranch = model->createBranch(lastBranch);
        readNodeAttr(atts);
    }
    else if (eName == "node" && (state == StateNode || state == StateMainNode)) {
        state = StateNode;
        lastBranch = model->createBranch(lastBranch);
        readNodeAttr(atts);
    }
    else if (eName == "properties") {
    }
    else if (eName == "map_styles") {
    }
    else if (eName == "font" && nodeLikeState())
    { 
        // FIXME-3 not implemented
        state = StateFont;
    }
    else if (eName == "edge" && nodeLikeState())
    {
         // FIXME-3 xlink not implemented
        state = StateEdge;
    }
    else if (eName == "hook" && nodeLikeState()) {
        state = StateHook;
    }
    else if (eName == "icon" && nodeLikeState()) {
        state = StateIcon;
        if (!atts.value("BUILTIN").isEmpty()) {
            QString f = atts.value("BUILTIN");
            QString v;
            if (f == "help")
                v = "questionmark";
            else if (f == "messagebox_warning")
                v = "freemind-warning";
            else if (f == "idea")
                v = "lamp";
            else if (f == "button_ok")
                v = "hook-green";
            else if (f == "button_cancel")
                v = "cross-red";
            else if (f.contains("full-"))
                v = f.replace("full-", "freemind-priority-");
            else if (f == "back")
                v = "freemind-back";
            else if (f == "forward")
                v = "freemind-forward";
            else if (f == "attach")
                v = "freemind-attach";
            else if (f == "ksmiletris")
                v = "smiley-good"; //
            else if (f == "clanbomber")
                v = "freemind-clanbomber";
            else if (f == "desktop_new")
                v = "freemind-desktopnew";
            else if (f == "flag")
                v = "freemind-flag";
            else if (f == "gohome")
                v = "freemind-gohome";
            else if (f == "kaddressbook")
                v = "freemind-kaddressbook";
            else if (f == "knotify")
                v = "freemind-knotify";
            else if (f == "korn")
                v = "freemind-korn";
            else if (f == "Mail")
                v = "freemind-mail";
            else if (f == "password")
                v = "freemind-password";
            else if (f == "pencil")
                v = "freemind-pencil";
            else if (f == "stop")
                v = "freemind-stop";
            else if (f == "wizard")
                v = "freemind-wizard";
            else if (f == "xmag")
                v = "freemind-xmag";
            else if (f == "bell")
                v = "freemind-bell";
            else if (f == "bookmark")
                v = "freemind-bookmark";
            else if (f == "penguin")
                v = "freemind-penguin";
            else if (f == "licq")
                v = "freemind-licq";
            else
                qWarning() << "parseFreemindHandler: Unknown icon found: " << f;

            lastBranch->activateStandardFlagByName(v);
        }
    }
    else if (eName == "arrowlink" && nodeLikeState()) {
        state = StateArrowLink;
    }
    else if (eName == "cloud" && nodeLikeState()) {
        state = StateCloud;
    }
    else if (eName == "richcontent" && nodeLikeState()) {
        state = StateRichContent;
        return readRichContentAttr(atts);
    }
    else if (eName == "html" && state == StateRichContent) {
        state = StateHtml;
        htmldata = "<" + eName;
        readHtmlAttr(atts);
        htmldata += ">";
    }
    else if (eName == "text" && state == StateHook) {
        state = StateText;
    }
    else if (state == StateHtml) {
        // accept all while in html mode,
        htmldata += "<" + eName;
        readHtmlAttr(atts);
        htmldata += ">";
    }
    else {
        // Usually we would return an error here
        // In order to not break with every new element in FreeMind or
        // FreePlane, better ignore the new element for now
        state = StateUnknown;
        qWarning()
            << "parseFreemindHandler: Unknown element found and ignoring:: "
            << eName;
    }
    return true;
}

bool parseFreemindHandler::endElement(const QString &, const QString &,
                                      const QString &eName)
{
    /* Testing
    QString h;
    lastBranch ? h = lastBranch->getHeadingPlain() : h = "";
    if (eName.contains("node"))
    qDebug() << "endElement </" << eName << ">  state=" << state << " lastBranch=" << h;
    */

    switch (state) {
        case StateMap:
            // Freemind does not have the two "extra" mainbranches used here,
            // so we have to update mapcenter
            model->emitDataChanged(mapCenter);

            // Remove helper branches, if not needed
            if (mainBranchLeft->childCount() == 0)
                model->deleteItem(mainBranchLeft);
            if (mainBranchRight->childCount() == 0)
                model->deleteItem(mainBranchRight);
            break;
        case StateCenter:
        case StateMainNode:
        case StateNode:
            model->emitDataChanged(lastBranch);
            lastBranch = (BranchItem *)lastBranch->parent();
            if (lastBranch) 
                lastBranch->setLastSelectedBranch(0);
            else
                qWarning() << "xml-vym:  lastBranch == nullptr";
            break;
        case StateRichContent:
            if (!htmldata.isEmpty()) {
                vymtext.setAutoText(htmldata);
                if (htmlPurpose == Node)
                    lastBranch->setHeading(vymtext);
                else if (htmlPurpose == Note)
                    lastBranch->setNote(vymtext);
            }
            break;
        case StateHtml:
            htmldata += "</" + eName + ">";
            if (eName == "html") {
                htmldata = htmldata.replace("<br></br>", "<br />");
                htmldata = htmldata.replace("\\n</p>", "</p>");
            }
            break;
        default:
            break;
    }
    state = stateStack.takeLast();
    return true;
}

bool parseFreemindHandler::characters(const QString &ch)
{
    //qDebug() << "characters \"" << qPrintable(ch) << "\"  state=" << state;

    QString ch_org = quoteMeta(ch);
    QString ch_simplified = ch.simplified();
    if (ch_simplified.isEmpty())
        return true;

    switch (state) {
    case StateInit:
        break;
    case StateMap:
        break;
    case StateNode:
        break;
    case StateCloud:
        break;
    case StateEdge:
        break;
    case StateIcon:
        break;
    case StateArrowLink:
        break;
    case StateFont:
        break;
    case StateHook:
        break;
    case StateText:
        lastBranch->setNote(ch_simplified);
        break;
    case StateHtml:
        htmldata += ch_org;
        break;
    case StateUnknown:
        break;
    default:
        return false;
    }
    return true;
}

QString parseFreemindHandler::errorString()
{
    return "the document is not in the Freemind file format";
}

bool parseFreemindHandler::readNodeAttr(const QXmlAttributes &a)
{
    if (state == StateMainNode)
    {
        // Freemind has a different concept for mainbranches
        // Move either to left or right side of mapcenter
        if (!a.value("POSITION").isEmpty()) {
            if (a.value("POSITION") == "left")
                model->relinkBranch(lastBranch, mainBranchLeft);
            else if (a.value("POSITION") == "right")
                model->relinkBranch(lastBranch, mainBranchRight);
        }
    }

    if (a.value("FOLDED") == "true")
        lastBranch->toggleScroll();

    if (!a.value("TEXT").isEmpty()) {
        lastBranch->setHeadingPlainText(
            a.value("TEXT")); // FIXME-3 what about RT?
        // model->setHeading (a.value ("TEXT"), lastBranch);
    }

    if (!a.value("COLOR").isEmpty())
        lastBranch->setHeadingColor(QColor(a.value("COLOR")));

    if (!a.value("LINK").isEmpty())
        lastBranch->setURL(a.value("LINK"));
    return true;
}

bool parseFreemindHandler::readRichContentAttr(const QXmlAttributes &a)
{
    if (a.value("TYPE") == "NODE")
        htmlPurpose = Node;
    else if (a.value("TYPE") == "NOTE")
        htmlPurpose = Note;
    else {
        htmlPurpose = Unknown;
        qWarning()
            << "parseFreemindHandler: Unknown purpose of richContent found: "
            << a.value("TYPE");
        ;
        // FIXME-3 Usually we would stop here, ignore for now
        // return false;
    }
    return true;
}
