#include <QDomDocument>
#include <QDateTime>
#include <QImageReader>

// MythTV headers
#include <mythuibutton.h>
#include <mythuibuttonlist.h>
#include <mythuitextedit.h>
#include <mythuicheckbox.h>
#include <mythuifilebrowser.h>
#include <mythmainwindow.h>
#include <mythdialogbox.h>
#include <mythuiimage.h>
#include <mythuitext.h>
#include <mythdate.h>
#include <mythcontext.h>
#include <mythdbcon.h>
#include <mythdirs.h>
#include <netutils.h>
#include <rssparse.h>
#include <mythdownloadmanager.h>
#include <mythsorthelper.h>

// RSS headers
#include "rsseditor.h"

#define LOC      QString("RSSEditor: ")
#define LOC_WARN QString("RSSEditor, Warning: ")
#define LOC_ERR  QString("RSSEditor, Error: ")

namespace
{
    const QString CEID_NEWIMAGE = "image";

    QStringList GetSupportedImageExtensionFilter()
    {
        QStringList ret;

        QList<QByteArray> exts = QImageReader::supportedImageFormats();
        foreach (auto & ext, exts)
            ret.append(QString("*.").append(ext));

        return ret;
    }
}

RSSEditPopup::~RSSEditPopup()
{
    if (m_manager)
    {
        m_manager->disconnect();
        m_manager->deleteLater();
        m_manager = nullptr;
    }
}

bool RSSEditPopup::Create(void)
{
    // Load the theme for this screen
    bool foundtheme =
        LoadWindowFromXML("netvision-ui.xml", "rsseditpopup", this);

    if (!foundtheme)
        return false;

    bool err = false;
    UIUtilE::Assign(this, m_urlEdit, "url", &err);
    UIUtilE::Assign(this, m_titleEdit, "title", &err);
    UIUtilE::Assign(this, m_descEdit, "description", &err);
    UIUtilE::Assign(this, m_authorEdit, "author", &err);
    UIUtilE::Assign(this, m_download, "download", &err);
    UIUtilE::Assign(this, m_okButton, "ok", &err);
    UIUtilE::Assign(this, m_cancelButton, "cancel", &err);
    UIUtilE::Assign(this, m_thumbButton, "preview_browse", &err);
    UIUtilE::Assign(this, m_thumbImage, "preview", &err);

    if (err)
    {
        LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'rsseditpopup'");
        return false;
    }

    connect(m_okButton, SIGNAL(Clicked()), this, SLOT(ParseAndSave()));
    connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(Close()));
    connect(m_thumbButton, SIGNAL(Clicked()), this, SLOT(DoFileBrowser()));

    m_urlEdit->SetMaxLength(0);
    m_titleEdit->SetMaxLength(255);
    m_descEdit->SetMaxLength(0);
    m_authorEdit->SetMaxLength(255);

    if (m_editing)
    {
        m_site = findByURL(m_urlText, VIDEO_PODCAST);

        m_urlEdit->SetText(m_urlText);
        m_titleEdit->SetText(m_site->GetTitle());
        m_descEdit->SetText(m_site->GetDescription());
        m_authorEdit->SetText(m_site->GetAuthor());

        QString thumb = m_site->GetImage();
        if (!thumb.isEmpty())
        {
            m_thumbImage->SetFilename(thumb);
            m_thumbImage->Load();
        }

        if (m_site->GetDownload())
            m_download->SetCheckState(MythUIStateType::Full);
    }

    BuildFocusList();

    return true;
}

bool RSSEditPopup::keyPressEvent(QKeyEvent *event)
{
    if (GetFocusWidget()->keyPressEvent(event))
        return true;

    QStringList actions;
    bool handled = GetMythMainWindow()->TranslateKeyPress("Internet Video",
                                                          event, actions);

    if (!handled && MythScreenType::keyPressEvent(event))
        handled = true;

    return handled;
}

void RSSEditPopup::ParseAndSave(void)
{
    if (m_editing)
    {
        QString title = m_titleEdit->GetText();
        QString desc = m_descEdit->GetText();
        QString author = m_authorEdit->GetText();
        QString link = m_urlEdit->GetText();
        QString filename = m_thumbImage->GetFilename();
        bool download = m_download->GetCheckState() == MythUIStateType::Full;

        removeFromDB(m_urlText, VIDEO_PODCAST);

        std::shared_ptr<MythSortHelper>sh = getMythSortHelper();
        RSSSite site(title, sh->doTitle(title), filename, VIDEO_PODCAST,
                     desc, link, author, download, MythDate::current());
        if (insertInDB(&site))
            emit Saving();
        Close();
    }
    else
    {
        m_manager = new QNetworkAccessManager();
        QUrl qurl(m_urlEdit->GetText());

        m_reply = m_manager->get(QNetworkRequest(qurl));

        connect(m_manager, SIGNAL(finished(QNetworkReply*)), this,
                           SLOT(SlotCheckRedirect(QNetworkReply*)));
    }
}

QUrl RSSEditPopup::redirectUrl(const QUrl& possibleRedirectUrl,
                               const QUrl& oldRedirectUrl)
{
    QUrl redirectUrl;
    if(!possibleRedirectUrl.isEmpty() && possibleRedirectUrl != oldRedirectUrl)
        redirectUrl = possibleRedirectUrl;
    return redirectUrl;
}

void RSSEditPopup::SlotCheckRedirect(QNetworkReply* reply)
{
    QVariant possibleRedirectUrl =
        reply->attribute(QNetworkRequest::RedirectionTargetAttribute);

    QUrl urlRedirectedTo;
    urlRedirectedTo = redirectUrl(
        possibleRedirectUrl.toUrl(), urlRedirectedTo);

    if (!urlRedirectedTo.isEmpty())
    {
        m_urlEdit->SetText(urlRedirectedTo.toString());
        m_manager->get(QNetworkRequest(urlRedirectedTo));
    }
    else
    {
//        urlRedirectedTo.clear();
        SlotSave(reply);
    }
    reply->deleteLater();
}

void RSSEditPopup::SlotSave(QNetworkReply* reply)
{
    QDomDocument document;
    document.setContent(reply->read(reply->bytesAvailable()), true);

    QString text = document.toString();

    QString title = m_titleEdit->GetText();
    QString description = m_descEdit->GetText();
    QString author = m_authorEdit->GetText();
    QString file = m_thumbImage->GetFilename();

    LOG(VB_GENERAL, LOG_DEBUG, QString("Text to Parse: %1").arg(text));

    QDomElement root = document.documentElement();
    QDomElement channel = root.firstChildElement ("channel");
    if (!channel.isNull())
    {
        Parse parser;
        if (title.isEmpty())
            title = channel.firstChildElement("title").text().trimmed();
        if (description.isEmpty())
            description = channel.firstChildElement("description").text();
        if (author.isEmpty())
            author = Parse::GetAuthor(channel);
        if (author.isEmpty())
            author = channel.firstChildElement("managingEditor").text();
        if (author.isEmpty())
            author = channel.firstChildElement("webMaster").text();

        QString thumbnailURL =
            channel.firstChildElement("image").attribute("url");
        if (thumbnailURL.isEmpty())
        {
            QDomElement thumbElem = channel.firstChildElement("image");
            if (!thumbElem.isNull())
                thumbnailURL = thumbElem.firstChildElement("url").text();
        }
        if (thumbnailURL.isEmpty())
        {
            QDomNodeList nodes = channel.elementsByTagNameNS(
                           "http://www.itunes.com/dtds/podcast-1.0.dtd",
                           "image");
            if (nodes.size())
            {
                thumbnailURL =
                    nodes.at(0).toElement().attributeNode("href").value();
                if (thumbnailURL.isEmpty())
                    thumbnailURL = nodes.at(0).toElement().text();
            }
        }

        bool download = m_download->GetCheckState() == MythUIStateType::Full;
        QDateTime updated = MythDate::current();
        QString filename("");

        if (!file.isEmpty())
            filename = file;
        else if (!thumbnailURL.isEmpty())
            filename = thumbnailURL;

        QString link = m_urlEdit->GetText();

        std::shared_ptr<MythSortHelper>sh = getMythSortHelper();
        RSSSite site(title, sh->doTitle(title), filename, VIDEO_PODCAST, description, link,
                     author, download, MythDate::current());
        if (insertInDB(&site))
            emit Saving();
    }

    Close();
}

void RSSEditPopup::DoFileBrowser()
{
    SelectImagePopup(GetConfDir() + "/MythNetvision" + "/sitecovers", *this,
                     CEID_NEWIMAGE);
}

void RSSEditPopup::SelectImagePopup(const QString &prefix,
                            QObject &inst, const QString &returnEvent)
{
    MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");

    auto *fb = new MythUIFileBrowser(popupStack, prefix);
    fb->SetNameFilter(GetSupportedImageExtensionFilter());
    if (fb->Create())
    {
        fb->SetReturnEvent(&inst, returnEvent);
        popupStack->AddScreen(fb);
    }
    else
        delete fb;
}

void RSSEditPopup::customEvent(QEvent *levent)
{
    if (levent->type() == DialogCompletionEvent::kEventType)
    {
        auto *dce = dynamic_cast<DialogCompletionEvent*>(levent);
        if ((dce != nullptr) && (dce->GetId() == CEID_NEWIMAGE))
        {
            m_thumbImage->SetFilename(dce->GetResultText());
            m_thumbImage->Load();
            m_thumbImage->Show();
        }
    }
}

RSSEditor::~RSSEditor()
{
    QMutexLocker locker(&m_lock);

    if (m_changed)
        emit ItemsChanged();
}

bool RSSEditor::Create(void)
{
    QMutexLocker locker(&m_lock);

    // Load the theme for this screen
    bool foundtheme = LoadWindowFromXML("netvision-ui.xml", "rsseditor", this);

    if (!foundtheme)
        return false;

    bool err = false;
    UIUtilE::Assign(this, m_sites, "sites", &err);
    UIUtilE::Assign(this, m_new, "new", &err);
    UIUtilE::Assign(this, m_delete, "delete", &err);
    UIUtilE::Assign(this, m_edit, "edit", &err);

    UIUtilW::Assign(this, m_image, "preview");
    UIUtilW::Assign(this, m_title, "title");
    UIUtilW::Assign(this, m_desc, "description");
    UIUtilW::Assign(this, m_url, "url");
    UIUtilW::Assign(this, m_author, "author");

    if (err)
    {
        LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'rsseditor'");
        return false;
    }

    connect(m_sites, SIGNAL(itemClicked(MythUIButtonListItem*)),
            this, SLOT(SlotEditSite(void)));

    connect(m_delete, SIGNAL(Clicked(void)),
            SLOT(SlotDeleteSite(void)));
    connect(m_edit, SIGNAL(Clicked(void)),
            SLOT(SlotEditSite(void)));
    connect(m_new, SIGNAL(Clicked(void)),
            SLOT(SlotNewSite(void)));

    connect(m_sites, SIGNAL(itemSelected(MythUIButtonListItem *)),
            SLOT(SlotItemChanged(void)));

    BuildFocusList();

    LoadData();

    if (m_sites->GetCount() == 0)
        SetFocusWidget(m_new);
    else
        SlotItemChanged();

    return true;
}

void RSSEditor::LoadData()
{
    qDeleteAll(m_siteList);
    m_siteList = findAllDBRSS();
    fillRSSButtonList();
    if (m_sites->GetCount() == 0)
    {
        m_edit->SetVisible(false);
        m_delete->SetVisible(false);
        m_sites->SetVisible(false);
    }
    else
    {
        m_edit->SetVisible(true);
        m_delete->SetVisible(true);
        m_sites->SetVisible(true);
    }
}

bool RSSEditor::keyPressEvent(QKeyEvent *event)
{
    if (GetFocusWidget()->keyPressEvent(event))
        return true;

    QStringList actions;
    bool handled = GetMythMainWindow()->TranslateKeyPress("Internet Video",
                                                          event, actions);

    for (int i = 0; i < actions.size() && !handled; i++)
    {
        QString action = actions[i];
        handled = true;

        if (action == "DELETE" && GetFocusWidget() == m_sites)
        {
            SlotDeleteSite();
        }
        else if (action == "EDIT" && GetFocusWidget() == m_sites)
        {
            SlotEditSite();
        }
        else
            handled = false;
    }


    if (!handled && MythScreenType::keyPressEvent(event))
        handled = true;

    return handled;
}

void RSSEditor::fillRSSButtonList()
{
    QMutexLocker locker(&m_lock);

    m_sites->Reset();

    foreach (auto & site, m_siteList)
    {
        auto *item = new MythUIButtonListItem(m_sites, site->GetTitle());
        item->SetText(site->GetTitle(), "title");
        item->SetText(site->GetDescription(), "description");
        item->SetText(site->GetURL(), "url");
        item->SetText(site->GetAuthor(), "author");
        item->SetData(QVariant::fromValue(site));
        item->SetImage(site->GetImage());
    }
}

void RSSEditor::SlotItemChanged()
{
    auto *site = m_sites->GetItemCurrent()->GetData().value<RSSSite*>();
    if (site)
    {
        if (m_image)
        {
            const QString& thumb = site->GetImage();

            m_image->Reset();

            if (!thumb.isEmpty())
            {
                m_image->SetFilename(thumb);
                m_image->Load();
            }
        }
        if (m_title)
            m_title->SetText(site->GetTitle());
        if (m_desc)
            m_desc->SetText(site->GetDescription());
        if (m_url)
            m_url->SetText(site->GetURL());
        if (m_author)
            m_author->SetText(site->GetAuthor());
    }
}

void RSSEditor::SlotDeleteSite()
{
    QMutexLocker locker(&m_lock);

    QString message =
        tr("Are you sure you want to unsubscribe from this feed?");

    MythScreenStack *m_popupStack =
        GetMythMainWindow()->GetStack("popup stack");

    auto *confirmdialog = new MythConfirmationDialog(m_popupStack,message);

    if (confirmdialog->Create())
    {
        m_popupStack->AddScreen(confirmdialog);

        connect(confirmdialog, SIGNAL(haveResult(bool)),
                SLOT(DoDeleteSite(bool)));
    }
    else
        delete confirmdialog;
}

void RSSEditor::SlotEditSite()
{
    QMutexLocker locker(&m_lock);

    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();

    auto *site = m_sites->GetItemCurrent()->GetData().value<RSSSite*>();
    if (site)
    {
        auto *rsseditpopup =
            new RSSEditPopup(site->GetURL(), true, mainStack, "rsseditpopup");

        if (rsseditpopup->Create())
        {
            connect(rsseditpopup, SIGNAL(Saving()), this, SLOT(ListChanged()));

            mainStack->AddScreen(rsseditpopup);
        }
        else
            delete rsseditpopup;
    }
}

void RSSEditor::SlotNewSite()
{
    QMutexLocker locker(&m_lock);

    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();

    auto *rsseditpopup = new RSSEditPopup("", false, mainStack, "rsseditpopup");

    if (rsseditpopup->Create())
    {
        connect(rsseditpopup, SIGNAL(Saving()), this, SLOT(ListChanged()));

        mainStack->AddScreen(rsseditpopup);
    }
    else
        delete rsseditpopup;
}

void RSSEditor::DoDeleteSite(bool remove)
{
    QMutexLocker locker(&m_lock);

    if (!remove)
        return;

    auto *site = m_sites->GetItemCurrent()->GetData().value<RSSSite*>();

    if (removeFromDB(site))
        ListChanged();
}

void RSSEditor::ListChanged()
{
    m_changed = true;
    LoadData();
}
