/*
 *   This file is part of Dianara
 *   Copyright 2012-2019  JanKusanagi JRR <jancoding@gmx.com>
 *
 *   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 2 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, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .
 */

#include "asactivity.h"

ASActivity::ASActivity(QVariantMap activityMap, QString userId,
                       QObject *parent) : QObject(parent)
{
    m_id = activityMap.value("id").toString();
    m_ownUserId = userId;

    // Get the author of the _activity_ (not the object)
    m_author = new ASPerson(activityMap.value("actor").toMap(), this);

    // Get the object included with the activity: the post itself, or whatever
    m_object = new ASObject(activityMap.value("object").toMap(), this);

    // If the object is a person, as in an activity where someone adds someone else
    if (m_object->getType() == QStringLiteral("person"))
    {
        m_personObject = new ASPerson(activityMap.value("object").toMap(), this);
    }
    else
    {
        // Otherwise, at least initialize empty, but valid
        m_personObject = new ASPerson(QVariantMap(), this);
    }

    // Get possible "target"
    m_target = new ASObject(activityMap.value("target").toMap(), this);

    // FIXME: add bools hasAuthor, hasObject and hasTarget, maybe?


    // Activity verb: post, share...
    m_verb = activityMap.value("verb").toString();

    if (m_verb == QStringLiteral("share"))
    {
        m_shared = true;
        m_sharedByName = m_author->getNameWithFallback();
        m_sharedById = m_author->getId();
        m_sharedByAvatar = m_author->getAvatarUrl();
    }
    else
    {
        m_shared = false;
    }


    // Timestamps
    m_createdAt = activityMap.value("published").toString();
    m_updatedAt = activityMap.value("updated").toString();

    // Software used to generate the activity: webUI, a client, a service...
    m_generator = activityMap.value("generator").toMap().value("displayName").toString();

    // Content of the activity, usually a description like "User followed someone"
    m_content = activityMap.value("content").toString();


    // Audience: To
    QVariantMap aToMap;
    foreach (const QVariant toVariant, activityMap.value("to").toList())
    {
        aToMap = toVariant.toMap();

        QString toId = aToMap.value("id").toString();
        if (toId == QStringLiteral("http://activityschema.org/collection/public"))
        {
            m_recipientsToString += QStringLiteral("<b>")
                                  + tr("Public")
                                  + QStringLiteral("</b>, ");
        }
        else
        {
            QString displayName = aToMap.value("displayName").toString().trimmed();
            // If name's empty, and ID is from a person
            if (displayName.isEmpty() && toId.startsWith(QStringLiteral("acct:")))
            {
                displayName = "&lt;" + ASPerson::cleanupId(toId) + "&gt;";
            }

#ifdef SHOWWRONGTOCC
            if (displayName.isEmpty()) // if STILL empty, some weirdness is there
            {
                displayName = "-?-";
            }
#endif

            if (!displayName.isEmpty())
            {
                if (ASPerson::cleanupId(toId) == m_ownUserId)
                {
                    displayName = "<b><big>" + displayName + "</big></b>";
                }

                m_recipientsToString += "<a href=\""
                                      + aToMap.value("url").toString() + "\">"
                                      + displayName + "</a>, ";
            }

            m_recipientsIdList.append(ASPerson::cleanupId(toId));
        }
    }
    m_recipientsToString.remove(-2, 2); // remove last comma and space


    // and Cc
    QVariantMap aCcMap;
    foreach (const QVariant ccVariant, activityMap.value("cc").toList())
    {
        aCcMap = ccVariant.toMap();

        QString ccId = aCcMap.value("id").toString();
        if (ccId == QStringLiteral("http://activityschema.org/collection/public"))
        {
            m_recipientsCcString += "<b>" + tr("Public") + "</b>, ";
        }
        else
        {
            QString displayName = aCcMap.value("displayName").toString().trimmed();
            // If name's empty, and ID is from a person
            if (displayName.isEmpty() && ccId.startsWith("acct:"))
            {
                displayName = "&lt;" + ASPerson::cleanupId(ccId) + "&gt;";
            }

#ifdef SHOWWRONGTOCC
            if (displayName.isEmpty()) // if STILL empty, for some reason...
            {
                displayName = "-?-";
            }
#endif

            if (!displayName.isEmpty())
            {
                if (ASPerson::cleanupId(ccId) == m_ownUserId)
                {
                    displayName = "<b><i><big>" + displayName + "</big></i></b>";
                }

                m_recipientsCcString += "<a href=\""
                                      + aCcMap.value("url").toString() + "\">"
                                      + displayName + "</a>, ";
            }

            m_recipientsIdList.append(ASPerson::cleanupId(ccId));
        }
    }
    m_recipientsCcString.remove(-2, 2);


    qDebug() << "ASActivity created" << m_id;
}



ASActivity::~ASActivity()
{
    qDebug() << "ASActivity destroyed" << m_id;
}



////// Getters!

ASPerson *ASActivity::author()
{
    return m_author;
}

ASObject *ASActivity::object()
{
    return m_object;
}

ASObject *ASActivity::target()
{
    return m_target;
}

ASPerson *ASActivity::personObject()
{
    return m_personObject;
}


QString ASActivity::getId()
{
    return m_id;
}

QString ASActivity::getVerb()
{
    return m_verb;
}

QString ASActivity::getGenerator()
{
    return m_generator;
}

QString ASActivity::getCreatedAt()
{
    return m_createdAt;
}

QString ASActivity::getUpdatedAt()
{
    return m_updatedAt;
}

QString ASActivity::getContent()
{
    return m_content;
}

QString ASActivity::getToString()
{
    return m_recipientsToString;
}

QString ASActivity::getCcString()
{
    return m_recipientsCcString;
}

QStringList ASActivity::getRecipientsIdList()
{
    return m_recipientsIdList;
}


bool ASActivity::isShared()
{
    return m_shared;
}

QString ASActivity::getSharedByName()
{
    return m_sharedByName;
}

QString ASActivity::getSharedById()
{
    return m_sharedById;
}

QString ASActivity::getSharedByAvatar()
{
    return m_sharedByAvatar;
}


/*
 * Create a string to be used as a tooltip
 *
 */
QString ASActivity::generateTooltip()
{
    QString activityTooltip;


    // Content
    QString activityObjectContent = m_object->getContent();

    if (m_object->getDeletedTime().isEmpty())
    {
        QString objectType = m_object->getType();
        if (ASObject::canDisplayObject(objectType)) // False also for empty type
        {
            if (!activityObjectContent.startsWith("<p"))
            {
                // Doesn't start with <p>, so add extra newline
                activityObjectContent.prepend("<br>");
            }

            activityObjectContent.prepend("[ "
                                          + ASObject::getTranslatedType(objectType)
                                          + " ]<br>");
        }
    }
    else
    {
        activityObjectContent.prepend("[" + m_object->getDeletedOnString() + "]");
    }


    if (!activityObjectContent.isEmpty())
    {
        // Object's author name and ID
        QString activityObjectAuthorName = m_object->author()->getNameWithFallback();
        QString activityObjectAuthorId = m_object->author()->getId();

        // If there's a name and/or an ID, show them
        if (!activityObjectAuthorName.isEmpty())
        {
            activityTooltip = "<b>" + activityObjectAuthorName + "</b><br>"
                              "<i>" + activityObjectAuthorId + "</i>"
                              "<hr><br>"; // horizontal rule as separator
        }

        // Title, only if there's content, too; redundant otherwise
        QString activityObjectTitle = m_object->getTitle();
        if (!activityObjectTitle.isEmpty())
        {
            activityTooltip.append("<b><u>"
                                   + activityObjectTitle
                                   + "</u></b>"
                                     "<br><br>");
        }

        activityTooltip.append(activityObjectContent + "<br>");

        // Object ID, might be interesting to show if it's a person
        if (m_object->getType() == QStringLiteral("person"))
        {
            activityTooltip.append("<br><i>"
                                   + m_object->getId()
                                   + "</i><br /><br />");
        }
    }


    // Target info
    QString activityTargetName = m_target->getTitle();
    QString activityTargetUrl = m_target->getUrl();
    if (activityTargetUrl.isEmpty())
    {
        activityTargetUrl = m_target->getId();
    }
    if (!activityTargetUrl.isEmpty())
    {
        activityTooltip.append("<hr>&gt;&gt; "); // Horizontal rule, and >>

        if (!activityTargetName.isEmpty())
        {
            activityTooltip.append(QString("<b>%1</b><br><i>%2</i>")
                                   .arg(activityTargetName)
                                   .arg(activityTargetUrl));
        }
        else
        {
            activityTooltip.append("<i>" + activityTargetUrl + "</i>");
        }

        // Show type of target object
        activityTooltip.append("<br>"
                               + ASObject::getTranslatedType(m_target->getType()));
    }


    // Remove last <br>, if needed
    if (activityTooltip.endsWith("<br>"))
    {
        activityTooltip.remove(-4, 4);
        // Check again, for double <br>'s
        if (activityTooltip.endsWith("<br>"))
        {
            activityTooltip.remove(-4, 4);
        }
    }


    activityTooltip = activityTooltip.trimmed();

    // If there's something, ensure it gets treated as HTML
    if (!activityTooltip.isEmpty())
    {
        activityTooltip.prepend("<b></b>");
    }

    return activityTooltip;
}



/*
 * Create a snippet of the activity and its object
 *
 */
QString ASActivity::generateSnippet(int charLimit)
{
    QString snippet;


    QString authorName = m_object->author()->getNameWithFallback();
    // If author name IS empty, probably means the author of the activity is the
    // author of the object (like posting a comment), so this wouldn't be useful
    if (m_object->author()->getId() != this->author()->getId()
     && !authorName.isEmpty())
    {
        /*
         * For some reason, when creating a structure like:
         *
         *   <i>Something by <b>name</b>:</i>
         *
         * a line break appears before the nickname.
         * Putting everything into a <p> fixes it; or making it piece by piece
         *
         */
        snippet.append("&diams; " // Diamond symbols -- Options: &bull; &equiv;
                       "<small><i>"
                       + tr("%1 by %2",
                            "1=kind of object: note, comment, etc; "
                            "2=author's name")
                         .arg(ASObject::getTranslatedType(m_object->getType()))
                         .arg("</i></small>"
                              "<b><small><i>"
                              + authorName
                              + "</i></small></b>")
                       + "<small><i>:</i></small>");
    }


    QString objectContent = m_object->getContent();
    if (!objectContent.isEmpty())
    {
        /*   //// Disabled: Showing the title is always redundant
             //// considering how the Pump.io core generates the
             //// activities descriptions.
        QString objectTitle = m_object->getTitle();
        if (!objectTitle.isEmpty())
        {
            snippet.append("<b><u>" + objectTitle + "</u></b><br>");
        }
        */

        QTextDocument textDocument;
        textDocument.setHtml(objectContent);

        //  Limit characters in snippet
        if (textDocument.characterCount() > charLimit)
        {
            QTextCursor cursor = textDocument.find(QRegExp(".*"), charLimit);
            cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
            cursor.removeSelectedText();
            cursor.insertHtml(" &nbsp;<b>[...]</b>");
        }

        snippet.append(MiscHelpers::cleanupHtml(textDocument.toHtml()));
    }

    return snippet.trimmed();
}


void ASActivity::setFilterMatches(QVariantMap newFilterMatches)
{
    m_filterMatches = newFilterMatches;
}


QVariantMap ASActivity::getFilterMatches()
{
    return m_filterMatches;
}
