/****************************************************************************
**
** Copyright (C) 2012 Róbert Márki
**
** This file is part of Web Feeds.
**
** Web Feeds 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 3 of the License, or
** (at your option) any later version.
**
** Web Feeds 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 Web Feeds.  If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/

#include "webfeedsapp.h"
#include <QDeclarativeContext>
#include <QDeclarativeEngine>
#include <QApplication>
#include <QPluginLoader>
#include <QMetaProperty>
#include <qplatformdefs.h>
#ifdef USE_MODELTEST
#   include "modeltest.h"
#endif
#ifdef MEEGO_EDITION_HARMATTAN
#   include <MDataUri/MDataUri>
#   include <maemo-meegotouch-interfaces/shareuiinterface.h>
#   include <QDBusMessage>
#   include <QDBusConnection>
#endif
#include <QDebug>

/*!
  \namespace WebFeeds
  \brief The main classes of the application.
*/
namespace WebFeeds
{
const char* WebFeedsApp::s_settingsAppletName       = "Web Feeds";
const char* WebFeedsApp::s_removeServiceMenuItem    = "RemoveServiceMenuItem";
const char* WebFeedsApp::s_aboutMenuItem            = "AboutMenuItem";
const char* WebFeedsApp::s_settingsMenuItem         = "SettingsMenuItem";

/*!
  \class WebFeedsApp
  \brief The WebFeedsApp class represenst the application itself.

  It's reponsebility is to add the authenticated feed service plugins to
  the object tree, and to provide general operations common to all service
  types.
*/
/*!
  \var WebFeedsApp::s_settingsAppletName
  The identifier of the settings applet.
*/
/*!
  \var WebFeedsApp::s_removeServiceMenuItem
  The name of the menu item responsible for removing
  the service of it's pageItem variable.
*/
/*!
  \var WebFeedsApp::s_aboutMenuItem
  The name of the menu item responsible for launching
  the about sheet.
*/
/*!
  \var WebFeedsApp::s_settingsMenuItem
  The name of the menu item responsible for launching
  the application's settings applet.
*/
/*!
  \fn WebFeedsApp::servicesChanged
  This signal is emitted when the list of available services changes.
*/
/*!
  \fn WebFeedsApp::pageItemModelChanged
  This signal is emitted pageItemModel property changes.
*/

/*!
  Constructs a WebFeedsApp object with the given \a parent.
*/
WebFeedsApp::WebFeedsApp(QObject *parent) :
    QObject(parent),
    m_rootItem(new PageItem)
{
}

/*!
  Returns the list of available services.
*/
QDeclarativeListProperty<AbstractFeedAggreagatorService> WebFeedsApp::services()
{
    return QDeclarativeListProperty<AbstractFeedAggreagatorService>(this, m_services);
}

/*!
  Returns the PageItemModel instance of the application.
*/
PageItemModel *WebFeedsApp::pageItemModel() const
{
    return m_model;
}

ApplicationSettings *WebFeedsApp::settings()
{
    return &m_settings;
}

/*!
  Returns the root item of the application.
*/
PageItem *WebFeedsApp::rootItem() const
{
    return m_rootItem.data();
}

/*!
  Return the names of the context menu items for the
  given \a item. The list contains the menu items specified
  by the given item's service and possibly some additional
  menu items added by the application itself.
*/
QStringList WebFeedsApp::contextMenuItems(PageItem *item)
{
    QStringList list;
    if(item)
    {
        AbstractFeedAggreagatorService* service = item->service();
        if(service != 0)
            list = service->contextMenuItems(PageItemWeakRef(item));
        if(item->parentItem() == m_rootItem)
        {
            list.append(WebFeedsApp::s_removeServiceMenuItem);
        }
    }
    return list;
}

/*!
  Return the names of the main menu items for the
  given \a item. The list contains the menu items specified
  by the given item's service and possibly some additional
  menu items added by the application itself.
*/
QStringList WebFeedsApp::menuItems(PageItem *item)
{
    QStringList list;
    if(item)
    {
        AbstractFeedAggreagatorService* service = item->service();
        if(service != 0)
            list = service->menuItems(PageItemWeakRef(item));
        if(item->parentItem() == m_rootItem)
        {
            list.append(WebFeedsApp::s_removeServiceMenuItem);
        }
        else if(item == m_rootItem)
        {            
            list.append(WebFeedsApp::s_aboutMenuItem);
            list.append(WebFeedsApp::s_settingsMenuItem);
        }
    }
    return list;
}

/*!
  Initializes the application. Creates the object tree and adds
  every authenticated service to it. It also constructs a PageItemModel
  instance which the UI can use to access the object tree.
*/
void WebFeedsApp::initialize(QDeclarativeEngine *engine)
{
    QDeclarativeEngine* declarativeEngine = engine;
    m_rootItem->setTitle(qApp->applicationName());
    m_model = new PageItemModel(m_rootItem, this);    
    m_model->setDynamicSortFilter(true);
#ifdef USE_MODELTEST
    new ModelTest(m_model, this);
#endif
    QSet<QString> propertyNames;
    foreach(QObject* plugin, QPluginLoader::staticInstances())
    {
        AbstractFeedAggreagatorService *service = qobject_cast<AbstractFeedAggreagatorService *>(plugin);
        if(service && !m_services.contains(service))
        {
            if(declarativeEngine != 0)
                declarativeEngine->addImageProvider(service->serviceId(), service);
            propertyNames += service->customItemTypeProperties();
            m_services.append(service);
            if(service->isAuthenticationDataSet())
            {
                service->enable(m_rootItem);
                service->setApplicationSettings(&m_settings);
                emit servicesChanged();
            }
            connect(service, SIGNAL(authenticationDataChanged(AbstractFeedAggreagatorService*)),
                    this, SLOT(onServiceAuthenticationDataChanged(AbstractFeedAggreagatorService*)));
            connect(service, SIGNAL(filterChanged()),
                    m_model, SLOT(onFilterChanged()));
        }
    }
    m_model->setupModelData(propertyNames);
}

/*!
  Returns true if the given \a service is enabled, otherwise returns false.
*/
bool WebFeedsApp::isServiceEnabled(AbstractFeedAggreagatorService *service)
{
    return (serviceItemIndex(service) != -1);
}

/*!
  Returns the index of the given \a service object. If the given \a service
  isn't found, -1 is returned.
*/
int WebFeedsApp::serviceItemIndex(AbstractFeedAggreagatorService *service)
{
    int ret = -1;
    for(int i = 0; i < m_rootItem->childCount(); ++i)
    {
        if(m_rootItem->childItem(i)->service() == service)
        {
            ret = i;
            break;
        }
    }
    return ret;
}

/*!
  If the given \a service is authenticated and it's not part of the object tree
  it will be added to it. If the given \a service is not authenticated and it's
  still part of the object tree, it will be removed from it.
*/
void WebFeedsApp::onServiceAuthenticationDataChanged(AbstractFeedAggreagatorService *service)
{
    if(service->isAuthenticationDataSet() && !isServiceEnabled(service))
    {
        service->enable(m_rootItem);        
        service->setApplicationSettings(&m_settings);
    }
    else if(!service->isAuthenticationDataSet() && isServiceEnabled(service))
    {
        service->disable();
    }
    emit servicesChanged();
}

/*!
  Shares a story with the given \a title and \a url with the help of
  harmattan's share-ui.
*/
void WebFeedsApp::shareStory(const QString& title, const QString& url) const
{
#ifdef MEEGO_EDITION_HARMATTAN
    MDataUri duri;
    duri.setMimeType ("text/x-url");
    duri.setTextData (title);
    duri.setAttribute ("title", url);
    if (duri.isValid())
    {
        QStringList items;
        items << duri.toString();
        ShareUiInterface shareIf("com.nokia.ShareUi");
        if (shareIf.isValid())
        {
            shareIf.share (items);
        }
    }
#else
    qDebug() << __FUNCTION__ << title << url;
#endif
}

/*!
  Launches the GConf settings applet associated with the
  application.
*/
void WebFeedsApp::launchSettingsApplet() const
{
#ifdef MEEGO_EDITION_HARMATTAN
    QDBusMessage message = QDBusMessage::createMethodCall(
                "com.nokia.DuiControlPanel",
                "/",
                "com.nokia.DuiControlPanelIf",
                "appletPage");
    QList<QVariant> args;
    args << WebFeedsApp::s_settingsAppletName;
    message.setArguments(args);
    QDBusConnection dBus = QDBusConnection::sessionBus();
    if (dBus.isConnected())
        dBus.send(message);
    else
        qDebug() << "Could not connect to dbus!";
#else
    qDebug() << __FUNCTION__;
#endif
}
} // namespace WebFeeds
