/*
 *   This file is part of Dianara
 *   Copyright 2012-2016  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 "minorfeeditem.h"


MinorFeedItem::MinorFeedItem(ASActivity *activity,
                             bool highlightedByFilter,
                             PumpController *pumpController,
                             GlobalObject *globalObject,
                             QWidget *parent) : QFrame(parent)
{
    this->pController = pumpController;
    this->globalObj = globalObject;

    this->itemIsNew = false;
    this->haveTargetAvatar = false;

    // This sizePolicy prevents cut messages, and the huge space at the end
    // of the feed, after clicking "Older Activities" several times
    this->setSizePolicy(QSizePolicy::Minimum,
                        QSizePolicy::Preferred);

    activity->setParent(this); // reparent the passed activity

    // Store activity ID so MinorFeed can reconstruct "next" url's
    this->activityId = activity->getId();

    QFont mainFont;
    mainFont.setPointSize(mainFont.pointSize() - 2);

    QString authorId = activity->author()->getId();

    avatarButton = new AvatarButton(activity->author(),
                                    this->pController,
                                    this->globalObj,
                                    this->globalObj->getMfAvatarSize(),
                                    this);


    createdAtTimestamp = activity->getCreatedAt();
    QString timestampTooltip = "<b>"
                               + Timestamp::localTimeDate(createdAtTimestamp)
                               + "</b>";

    QString generator = activity->getGenerator();
    if (!generator.isEmpty())
    {
        timestampTooltip.append("<br>"
                                + tr("Using %1",
                                     "Application used to generate this activity")
                                  .arg(generator));
    }

    QString toField = activity->getToString();
    QString ccField = activity->getCCString();
    if (!toField.isEmpty() || !ccField.isEmpty())
    {
        timestampTooltip.append("<br>"); // Extra separation before To or Cc

        if (!toField.isEmpty())
        {
            timestampTooltip.append("<br>"
                                    + tr("To: %1",
                                         "1=people to whom this activity was sent")
                                      .arg(toField));
        }
        if (!ccField.isEmpty())
        {
            timestampTooltip.append("<br>"
                                    + tr("Cc: %1",
                                         "1=people to whom this activity was sent as CC")
                                      .arg(ccField));
        }
    }

    timestampLabel = new QLabel(this);
    mainFont.setBold(true);
    timestampLabel->setFont(mainFont);
    timestampLabel->setWordWrap(true);
    timestampLabel->setToolTip(timestampTooltip.trimmed());
    timestampLabel->setAlignment(Qt::AlignCenter);
    timestampLabel->setAutoFillBackground(true);
    timestampLabel->setForegroundRole(QPalette::Text);
    timestampLabel->setBackgroundRole(QPalette::Base);
    timestampLabel->setFrameStyle(QFrame::Panel | QFrame::Raised);
    this->setFuzzyTimeStamp();


    // The description itself, like "JaneDoe updated a note",
    activityDescriptionLabel = new QLabel(this); // To be filled later
    QFont descriptionFont;
    descriptionFont.fromString(globalObj->getMinorFeedFont());
    activityDescriptionLabel->setWordWrap(true);
    activityDescriptionLabel->setOpenExternalLinks(true);
    activityDescriptionLabel->setAlignment(Qt::AlignTop);
    activityDescriptionLabel->setSizePolicy(QSizePolicy::Ignored,
                                            QSizePolicy::MinimumExpanding);
    activityDescriptionLabel->setFont(descriptionFont);
    connect(activityDescriptionLabel, SIGNAL(linkHovered(QString)),
            this, SLOT(showUrlInfo(QString)));

    // Tooltip contents
    QString activityTooltip = activity->generateTooltip();
    if (!activityTooltip.isEmpty())
    {
        // Set the activity info as tooltip for description label
        this->activityDescriptionLabel->setToolTip(activityTooltip);

        // Set a different mouse cursor for the description label, as a hint to wait for tooltip info
        this->activityDescriptionLabel->setCursor(Qt::WhatsThisCursor);
    }


    originalObjectMap = activity->object()->getOriginalObject();

    inReplyToMap = activity->object()->getInReplyTo();
    QString inReplyToAuthorId = ASPerson::cleanupId(inReplyToMap.value("author").toMap()
                                                                .value("id").toString());



    // Highlight this item if it's about the user, with different colors
    itemHighlightType = -1; // False

    // We are in the recipient list of the activity
    if (activity->getRecipientsIdList().contains(pController->currentUserId()))
    {
        itemHighlightType = 0;
    }

    // Activity is in reply to something made by us
    if (inReplyToAuthorId == pController->currentUserId())
    {
        itemHighlightType = 1;
    }

    // We are the object; someone added us, etc.
    if (activity->object()->getId() == pController->currentUserId())
    {
        itemHighlightType = 2;
    }

    // The object is ours; someone favorited our note, or something
    if (activity->object()->author()->getId() == pController->currentUserId())
    {
        itemHighlightType = 3;
    }

    //// Special case: highlighting the item because there's a filter rule for it
    if (highlightedByFilter && itemHighlightType == -1) // Only if there's no other reason for HL
    {
        itemHighlightType = 4;
    }


    if (itemHighlightType != -1)
    {
        // Unless the user ID is also empty!
        if (!pController->currentUserId().isEmpty())
        {
            QString highlightItemColor = this->globalObj->getColor(itemHighlightType);

            if (QColor::isValidColor(highlightItemColor)) // Valid color
            {
                // CSS for horizontal gradient from configured color to transparent
                QString css = QString("MinorFeedItem "
                                      "{ background-color: "
                                      "qlineargradient(spread:pad, "
                                      "x1:0, y1:0, x2:1, y2:0, "
                                      "stop:0 %1, stop:1 rgba(0, 0, 0, 0)); "
                                      "}")
                              .arg(highlightItemColor);

                this->setStyleSheet(css);
            }
            else // If there's no valid color, highlight with a border
            {
                this->setFrameStyle(QFrame::Panel);
            }
        }
    }


    // Set the activity description with optional snippet
    QString activityDescription = activity->getContent();


    // Add a snippet if configured to do so
    if (this->globalObj->getMinorFeedSnippetsType() != 3) // 3=Never
    {
        if (this->globalObj->getMinorFeedSnippetsType() == 2 // 2=Always
         || this->itemHighlightType != -1)       // 0/1/2 and it's highlighted
        {
            if (this->globalObj->getMinorFeedSnippetsType() > 0  // Always or any highlighted
             || authorId != pController->currentUserId())        // or highlighted but not ours (0)
            {
                // FIXME 1.3.5: fix this spaghetti mess!!
                // TODO: option to not show when the object of the activity is ours
                // i.e. "JohnDoe liked a note", our note

                int snippetCharLimit;
                if (this->itemHighlightType == -1)
                {
                    snippetCharLimit = globalObj->getSnippetsCharLimit();
                }
                else
                {
                    snippetCharLimit = globalObj->getSnippetsCharLimitHl();
                }

                QString snippet = activity->generateSnippet(snippetCharLimit);
                if (!snippet.isEmpty())
                {
                    activityDescription.append("&nbsp;<hr>" + snippet);
                }
            }
        }
    }

    this->activityDescriptionLabel->setText(activityDescription);




    //////////////////////////////////////////////////////// Layout
    leftLayout = new QVBoxLayout();
    leftLayout->setAlignment(Qt::AlignTop);
    leftLayout->setContentsMargins(1, 0, 1, 0);
    leftLayout->setSpacing(1);
    leftLayout->addWidget(avatarButton, 0, Qt::AlignTop | Qt::AlignLeft);
    leftLayout->addStretch(0);



    // Original post available (inReplyTo) or object available (note, image...)
    if (!inReplyToMap.isEmpty()
        || (ASObject::canDisplayObject(activity->object()->getType())
            && activity->object()->getDeletedTime().isEmpty())
       )
    {
        this->openButton = new QPushButton("+", this);
        openButton->setSizePolicy(QSizePolicy::Ignored,
                                  QSizePolicy::Maximum);
        openButton->setToolTip("<b></b>"
                               + tr("Open referenced post"));
        connect(openButton, SIGNAL(clicked()),
                this, SLOT(openOriginalPost()));
        leftLayout->addWidget(openButton, 0, Qt::AlignHCenter);
    }


    rightLowerLayout = new QHBoxLayout();
    rightLowerLayout->setContentsMargins(0, 0, 0, 0);
    rightLowerLayout->addWidget(activityDescriptionLabel, 1);
    // This may also contain an AvatarButton for an "object person"

    rightLayout = new QVBoxLayout();
    rightLayout->setAlignment(Qt::AlignTop);
    rightLayout->addWidget(timestampLabel);
    rightLayout->addLayout(rightLowerLayout);

    // If the object is a person, such as someone following someone else, add an AvatarButton for them
    if (activity->object()->getType() == "person")
    {
        ASPerson *personObject = activity->personObject();
        if (personObject->getId() != authorId) // avoid cases like "JohnDoe updated JohnDoe"
        {
            this->haveTargetAvatar = true;
            this->targetAvatarButton = new AvatarButton(personObject,
                                                        this->pController,
                                                        this->globalObj,
                                                        globalObj->getMfAvatarSize(), // QSize(28,28)
                                                        this);
            rightLowerLayout->addWidget(targetAvatarButton, 0, Qt::AlignBottom);
        }
    }


    mainLayout = new QHBoxLayout();
    mainLayout->setContentsMargins(2, 1, 2, 4);
    if (authorId == pController->currentUserId())
    {
        mainLayout->addLayout(rightLayout, 20);
        mainLayout->addLayout(leftLayout,  1);
    }
    else // Normal item, not ours
    {
        mainLayout->addLayout(leftLayout,  1);
        mainLayout->addLayout(rightLayout, 20);
    }
    this->setLayout(mainLayout);

    qDebug() << "MinorFeedItem created";
}



MinorFeedItem::~MinorFeedItem()
{
    qDebug() << "MinorFeedItem destroyed";
}


/*
 * Pseudo-highlight for new items
 *
 */
void MinorFeedItem::setItemAsNew(bool isNew, bool informFeed)
{
    itemIsNew = isNew;

    if (itemIsNew)
    {
        this->setAutoFillBackground(true);
        this->setBackgroundRole(QPalette::Mid);

        timestampLabel->setStyleSheet("QLabel "
                                      "{ background-color: qlineargradient(spread:pad,"
                                      "                    x1:0, y1:0, x2:1, y2:0,"
                                      "                    stop:0   palette(highlight),"
                                      "                    stop:0.2 palette(base),"
                                      "                    stop:0.8 palette(base),"
                                      "                    stop:1   palette(highlight));"
                                      "}"
                                      "QLabel:hover "
                                      "{ color: palette(highlighted-text);   "
                                      "  background-color: palette(highlight)"
                                      "}");
    }
    else
    {
        this->setAutoFillBackground(false);
        this->setBackgroundRole(QPalette::Window);

        timestampLabel->setStyleSheet("QLabel:hover "
                                      "{ color: palette(highlighted-text);   "
                                      "  background-color: palette(highlight)"
                                      "}");

        if (informFeed)
        {
            bool wasHighlighted = false;
            if (this->itemHighlightType != -1)
            {
                wasHighlighted = true;
            }

            emit itemRead(wasHighlighted);
        }
    }
}

bool MinorFeedItem::isNew()
{
    return this->itemIsNew;
}


/*
 * Set/Update the fuzzy timestamp
 *
 * This will be called from time to time
 *
 */
void MinorFeedItem::setFuzzyTimeStamp()
{
    this->timestampLabel->setText(Timestamp::fuzzyTime(createdAtTimestamp));
}

void MinorFeedItem::syncAvatarFollowState()
{
    this->avatarButton->syncFollowState();
    if (haveTargetAvatar)
    {
        this->targetAvatarButton->syncFollowState();
    }
}


int MinorFeedItem::getItemHighlightType()
{
    return this->itemHighlightType;
}

QString MinorFeedItem::getActivityId()
{
    return this->activityId;
}



/****************************************************************************/
/******************************** SLOTS *************************************/
/****************************************************************************/



void MinorFeedItem::openOriginalPost()
{
    // Create a fake activity for the object
    QVariantMap originalPostMap;
    if (!inReplyToMap.isEmpty())
    {
        originalPostMap.insert("object", this->inReplyToMap);
        originalPostMap.insert("actor",
                               this->inReplyToMap.value("author").toMap());
    }
    else
    {
        originalPostMap.insert("object", this->originalObjectMap);
        originalPostMap.insert("actor",
                               this->originalObjectMap.value("author").toMap());
    }

    ASActivity *originalPostActivity = new ASActivity(originalPostMap,
                                                      pController->currentUserId(),
                                                      this);

    Post *referencedPost = new Post(originalPostActivity,
                                    false, // Not highlighted
                                    true,  // Post is standalone
                                    pController,
                                    globalObj,
                                    this->parentWidget()); // Pass parent widget (MinorFeed) instead
                                                           // of 'this', so it won't be killed by reloads
    referencedPost->show();
    connect(pController, SIGNAL(commentsReceived(QVariantList,QString)),
            referencedPost, SLOT(setAllComments(QVariantList,QString)));
    referencedPost->getAllComments();
}



void MinorFeedItem::showUrlInfo(QString url)
{
    if (!url.isEmpty())
    {
        this->pController->showTransientMessage(url);

        qDebug() << "Link hovered in Minor Feed:" << url;
    }
    else
    {
        this->pController->showTransientMessage("");
    }
}


/****************************************************************************/
/******************************* PROTECTED **********************************/
/****************************************************************************/


/*
 * On mouse click in any part of the item, set it as read
 *
 */
void MinorFeedItem::mousePressEvent(QMouseEvent *event)
{
    if (itemIsNew)
    {
        this->setItemAsNew(false, // Mark as not new
                           true); // Inform the feed

        // Avoid flickering of the "new" effect later
        this->timestampLabel->repaint();
    }

    event->accept();
}


/*
 * Ensure URL info in statusbar is hidden when the mouse leaves the item
 *
 */
void MinorFeedItem::leaveEvent(QEvent *event)
{
    this->pController->showTransientMessage("");

    event->accept();
}
