/*
 *   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 "asobject.h"

ASObject::ASObject(QVariantMap objectMap,
                   QObject *parent) : QObject(parent)
{
    m_originalObjectMap = objectMap;

    /// Meta information
    m_id = ASPerson::cleanupId(objectMap.value("id").toString());

    m_type = objectMap.value("objectType").toString();
    m_url = objectMap.value("url").toString();
    m_createdAt = objectMap.value("published").toString();
    m_updatedAt = objectMap.value("updated").toString();

    // FIXME: still missing some fields...
    QVariantMap locationMap = objectMap.value("location").toMap();
    m_locationName = locationMap.value("displayName").toString();
    m_locationFormatted = locationMap.value("address").toMap()
                                     .value("formatted").toString();
    m_locationCountry = locationMap.value("address").toMap()
                                   .value("country").toString();


    // Author
    m_author = new ASPerson(objectMap.value("author").toMap(), this);

    // This will hold the date when the object was deleted, or empty if it wasn't
    m_deleted = objectMap.value("deleted").toString();

    m_liked = objectMap.value("liked").toBool();

    // The object to which this one replies, if any (note to which a comment replies, etc)
    m_inReplyToMap = objectMap.value("inReplyTo").toMap();


    ///
    /// End of "meta"; Start of content
    ///


    if (m_type == QStringLiteral("image"))
    {
        /* Get the "small" version.
         * See if there's a proxy URL for the image first
         * (for private images on remote servers)
         */
        qDebug() << "Trying Proxyed thumbnail image";
        m_smallImageUrl = objectMap.value("image").toMap()
                                   .value("pump_io").toMap()
                                   .value("proxyURL").toString();

        // And if that's empty, use regular image->url
        if (m_smallImageUrl.isEmpty())
        {
            qDebug() << "Trying direct thumbnail image";
            m_smallImageUrl = objectMap.value("image").toMap()
                                       .value("url").toString();
        }


        // Same for the full size image
        m_imageUrl = objectMap.value("fullImage").toMap()
                              .value("pump_io").toMap()
                              .value("proxyURL").toString();
        qDebug() << "Trying Proxyed fullImage";

        // If that's empty, use regular fullImage->url field
        if (m_imageUrl.isEmpty())
        {
            qDebug() << "Trying direct fullImage";
            m_imageUrl = objectMap.value("fullImage").toMap()
                                  .value("url").toString();
        }

        m_imageWidth = objectMap.value("fullImage").toMap()
                                .value("width").toInt();
        m_imageHeight = objectMap.value("fullImage").toMap()
                                 .value("height").toInt();

        // If it's STILL empty, use the thumbnail also as full image
        if (m_imageUrl.isEmpty())
        {
            m_imageUrl = m_smallImageUrl;
            m_imageWidth = objectMap.value("image").toMap()
                                    .value("width").toInt();
            m_imageHeight = objectMap.value("image").toMap()
                                     .value("height").toInt();
        }        

        // And if there's no small image for some reason, use the full one as thumbnail
        if (m_smallImageUrl.isEmpty())
        {
            m_smallImageUrl = m_imageUrl;
        }

        qDebug() << "postImage:" << m_imageUrl << "> Small:" << m_smallImageUrl;

        // To have a filename with extension, even when downloading from proxyURL's
        m_attachmentPureUrl = objectMap.value("fullImage").toMap()
                                       .value("url").toString();
        if (m_attachmentPureUrl.isEmpty())
        {
            m_attachmentPureUrl = objectMap.value("image").toMap()
                                           .value("url").toString();
        }
    }


    // Get audio file URL
    if (m_type == QStringLiteral("audio"))
    {
        // To have a filename with extension, even when downloading from proxyURL's
        m_attachmentPureUrl = objectMap.value("stream").toMap()
                                       .value("url").toString();

        m_audioUrl = objectMap.value("stream").toMap()
                              .value("pump_io").toMap()
                              .value("proxyURL").toString();
        if (m_audioUrl.isEmpty())
        {
            qDebug() << "No proxyed link to audio, fetching regular link";
            m_audioUrl = m_attachmentPureUrl;
        }
    }

    // Get video file URL
    if (m_type == QStringLiteral("video"))
    {
        // To have a filename with extension, even when downloading from proxyURL's
        m_attachmentPureUrl = objectMap.value("stream").toMap()
                                       .value("url").toString();

        m_videoUrl = objectMap.value("stream").toMap()
                              .value("pump_io").toMap()
                              .value("proxyURL").toString();
        if (m_videoUrl.isEmpty())
        {
            qDebug() << "No proxyed link to video, fetching regular link";
            m_videoUrl = m_attachmentPureUrl;
        }
    }

    // Get general file URL
    if (m_type == QStringLiteral("file"))
    {
        // To have a filename with extension, even when downloading from proxyURL's
        m_attachmentPureUrl = objectMap.value("fileUrl").toString();

        // FIXME: there are no proxyURL for misc files ATM; not my fault though =)
        m_fileUrl = objectMap.value("fileUrl").toMap()
                             .value("pump_io").toMap()
                             .value("proxyURL").toString();
        if (m_fileUrl.isEmpty())
        {
            qDebug() << "No proxyed link to general file, fetching regular link";
            m_fileUrl = m_attachmentPureUrl;
        }

        m_mimeType = objectMap.value("mimeType").toString();
        qDebug() << "File mimeType:" << m_mimeType;
    }


    // If it's a group, get member count, etc.
    if (m_type == QStringLiteral("group"))
    {
        m_memberCount = objectMap.value("members").toMap()
                                 .value("totalItems").toInt();
        m_memberUrl = objectMap.value("members").toMap()
                               .value("url").toString();
    }



    // Title can be in non-image posts, too!
    m_title = objectMap.value("displayName").toString().trimmed();
    m_summary = objectMap.value("summary").toString();
    m_content = objectMap.value("content").toString();

    m_likesCount = objectMap.value("likes").toMap().value("totalItems").toInt();
    m_commentsCount = objectMap.value("replies").toMap().value("totalItems").toInt();
    m_sharesCount = objectMap.value("shares").toMap().value("totalItems").toInt();

    // Get last likes, comments and shares list here, used from Post()
    m_lastLikesList = objectMap.value("likes").toMap().value("items").toList();
    m_lastCommentsList = objectMap.value("replies").toMap().value("items").toList();
    m_lastSharesList = objectMap.value("shares").toMap().value("items").toList();

    m_proxiedUrls = false;

    // Get URL for likes; first, proxyURL if it exists
    m_likesUrl = objectMap.value("likes").toMap().value("pump_io").toMap()
                                                 .value("proxyURL").toString();
    // If still empty, get regular URL (that means the post is in the same server we are)
    if (m_likesUrl.isEmpty())
    {
        m_likesUrl = objectMap.value("likes").toMap().value("url").toString();
    }

    // Get URL for comments; first, proxyURL if it exists
    m_commentsUrl = objectMap.value("replies").toMap().value("pump_io").toMap()
                                                      .value("proxyURL").toString();
    if (m_commentsUrl.isEmpty()) // If still empty, get regular URL
    {
        m_commentsUrl = objectMap.value("replies").toMap().value("url").toString();
    }
    else
    {
        m_proxiedUrls = true;
    }

    // FIXME: get sharesUrl...

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

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



void ASObject::updateAuthorFromPerson(ASPerson *person)
{
    m_author->updateDataFromPerson(person);
}



/////// Getters

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

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

QString ASObject::getType()
{
    return m_type;
}

QString ASObject::getTranslatedType(QString typeString)
{
    QString translatedTypeString;

    if (typeString == QStringLiteral("note"))
    {
        translatedTypeString = tr("Note",
                                  "Noun, an object type");
    }
    else if (typeString == QStringLiteral("article"))
    {
        translatedTypeString = tr("Article",
                                  "Noun, an object type");
    }
    else if (typeString == QStringLiteral("image"))
    {
        translatedTypeString = tr("Image",
                                  "Noun, an object type");
    }
    else if (typeString == QStringLiteral("audio"))
    {
        translatedTypeString = tr("Audio",
                                  "Noun, an object type");
    }
    else if (typeString == QStringLiteral("video"))
    {
        translatedTypeString = tr("Video",
                                  "Noun, an object type");
    }
    else if (typeString == QStringLiteral("file"))
    {
        translatedTypeString = tr("File",
                                  "Noun, an object type");
    }
    else if (typeString == QStringLiteral("comment"))
    {
        translatedTypeString = tr("Comment",
                                  "Noun, as in object type: a comment");
    }
    else if (typeString == QStringLiteral("group"))
    {
        translatedTypeString = tr("Group",
                                  "Noun, an object type");
    }
    else if (typeString == QStringLiteral("collection"))
    {
        translatedTypeString = tr("Collection",
                                  "Noun, an object type");
    }
    else
    {
        translatedTypeString = tr("Other",
                                  "As in: other type of post")
                               + " (" + typeString + ")";
    }

    return translatedTypeString;
}


QString ASObject::getUrl()
{
    return m_url;
}

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

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

QString ASObject::getLocationName()
{
    return m_locationName;
}

QString ASObject::getLocationFormatted()
{
    return m_locationFormatted;
}

QString ASObject::getLocationCountry()
{
    return m_locationCountry;
}

QString ASObject::getLocationTooltip()
{
    QString locationTooltip = m_locationFormatted;

    if (!m_locationCountry.isEmpty())
    {
        if (!locationTooltip.isEmpty())
        {
            locationTooltip.append("\n");
        }

        locationTooltip.append("(" + m_locationCountry +  ")");
    }

    // If still empty, return informational string
    if (locationTooltip.isEmpty())
    {
        locationTooltip = tr("No detailed location");
    }

    return locationTooltip;
}


QString ASObject::getDeletedTime()
{
    return m_deleted;
}


QString ASObject::getDeletedOnString()
{
    QString deletedOnString;
    if (!m_deleted.isEmpty())
    {
        deletedOnString = this->makeDeletedOnString(m_deleted);
    }

    return deletedOnString;
}

QString ASObject::makeDeletedOnString(QString deletionTime)
{
    return tr("Deleted on %1").arg(Timestamp::localTimeDate(deletionTime));
}


bool ASObject::isLiked()
{
    return m_liked;
}


QString ASObject::getTitle()
{
    return m_title;
}

QString ASObject::getSummary()
{
    return m_summary;
}

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

QString ASObject::getImageUrl()
{
    return m_imageUrl;
}

QString ASObject::getSmallImageUrl()
{
    return m_smallImageUrl;
}

int ASObject::getImageWidth()
{
    return m_imageWidth;
}

int ASObject::getImageHeight()
{
    return m_imageHeight;
}

QString ASObject::getAudioUrl()
{
    return m_audioUrl;
}

QString ASObject::getVideoUrl()
{
    return m_videoUrl;
}

QString ASObject::getFileUrl()
{
    return m_fileUrl;
}

QString ASObject::getMimeType()
{
    return m_mimeType;
}

QString ASObject::getAttachmentPureUrl()
{
    return m_attachmentPureUrl;
}

int ASObject::getMemberCount()
{
    return m_memberCount;
}

QString ASObject::getMemberUrl()
{
    return m_memberUrl;
}

int ASObject::getLikesCount()
{
    return m_likesCount;
}

int ASObject::getCommentsCount()
{
    return m_commentsCount;
}

int ASObject::getSharesCount()
{
    return m_sharesCount;
}

bool ASObject::hasProxiedUrls()
{
    return m_proxiedUrls;
}

QVariantList ASObject::getLastLikesList()
{
    return m_lastLikesList;
}

QVariantList ASObject::getLastCommentsList()
{
    return m_lastCommentsList;
}

QVariantList ASObject::getLastSharesList()
{
    return m_lastSharesList;
}

QString ASObject::getLikesUrl()
{
    return m_likesUrl;
}

QString ASObject::getCommentsUrl()
{
    return m_commentsUrl;
}

QString ASObject::getSharesUrl()
{
    return m_sharesUrl;
}

QVariantMap ASObject::getOriginalObject()
{
    return m_originalObjectMap;
}

QVariantMap ASObject::getInReplyTo()
{
    return m_inReplyToMap;
}

QString ASObject::getInReplyToId()
{
    return m_inReplyToMap.value("id").toString();
}


/*
 * This version should be deprecated soon -- WIP
 *
 */
QString ASObject::personStringFromList(QVariantList variantList, int count)
{
    QString personString;

    foreach (const QVariant listItem, variantList)
    {
        QVariantMap itemMap = listItem.toMap();

        QString name = itemMap.value("displayName").toString();
        if (name.isEmpty())
        {
            name = ASPerson::cleanupId(itemMap.value("id").toString()); // fallback
        }
        QString profileUrl = itemMap.value("url").toString();

        personString.prepend("<a href=\"" + profileUrl + "\">"
                             + name + "</a>, "); // Reverse order
    }

    int remainingCount = count - variantList.size();

    // Add "and $COUNT other"
    if (count != -1 && remainingCount > 0)
    {
        if (remainingCount == 1)
        {
            personString.append(tr("and one other"));
        }
        else
        {
            personString.append(tr("and %1 others").arg(remainingCount));
        }
    }
    else
    {
        // Remove last comma and space
        personString.remove(-2, 2);
    }


    return personString;
} // deprecating... WIP



QVariantMap ASObject::simplePersonMapFromList(QVariantList variantList)
{
    QVariantMap map;

    // Read the list in reverse order:

    for (int position = variantList.size() - 1; position >= 0; --position)
    {
        QVariantMap itemMap = variantList.at(position).toMap();

        QString id = ASPerson::cleanupId(itemMap.value("id").toString());
        QString name = itemMap.value("displayName").toString();
        if (name.isEmpty())
        {
            name = id; // fallback
        }
        QString profileUrl = itemMap.value("url").toString();

        ASObject::addOnePersonToSimpleMap(id, name, profileUrl,
                                          &map);
    }

    return map;
}


void ASObject::addOnePersonToSimpleMap(QString personId, QString personName,
                                       QString personUrl, QVariantMap *personMap)
{
    personMap->insert(personId, "<a href=\"" + personUrl + "\">"
                                + personName + "</a>");
}


QString ASObject::personStringFromSimpleMap(QVariantMap personMap,
                                            int totalCount)
{
    QString personString;

    foreach (const QString key, personMap.keys())
    {
        personString.append(personMap.value(key).toString() + ", ");
    }

    const int remainingCount = totalCount - personMap.keys().length();

    // Add "and $COUNT other"
    if (remainingCount > 0)
    {
        if (remainingCount == 1)
        {
            personString.append(tr("and one other"));
        }
        else
        {
            personString.append(tr("and %1 others").arg(remainingCount));
        }
    }
    else
    {
        // Remove last comma and space
        personString.remove(-2, 2);
    }

    return personString;
}



/*
 * Returns true if objectType is one of the types that Post() can display
 *
 *
 */
bool ASObject::canDisplayObject(QString objectType)
{
    bool canDisplay = false;

    if (objectType == QStringLiteral("note")
     || objectType == QStringLiteral("article")
     || objectType == QStringLiteral("image")
     || objectType == QStringLiteral("audio")
     || objectType == QStringLiteral("video")
     || objectType == QStringLiteral("file")
     || objectType == QStringLiteral("comment")
     || objectType == QStringLiteral("group"))
    {
        canDisplay = true;
    }
    else
    {
        qDebug() << "ASObject::canDisplayObject() - Unsupported:"
                 << objectType;
    }

    return canDisplay;
}
