/*
 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 * This component and the accompanying materials are made available
 * under the terms of "Eclipse Public License v1.0"
 * which accompanies this distribution, and is available
 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
 *
 * Initial Contributors:
 * Nokia Corporation - initial contribution.
 *
 * Contributors:
 *
 * Description: Base for menu view states.
 *
 */

#include <QScopedPointer>
#include <QStateMachine>
#include <HbMessageBox>
#include <HbParameterLengthLimiter>
#include <HbAction>
#include <HbMenu>
#include <HbAbstractViewItem>
#include <HbView>
#include <HbListView>

#include <canotifier.h>

#include "hsbaseviewstate.h"
#include "hsmenueventfactory.h"
#include "hsmenudialogfactory.h"
#include "hsmenuitemmodel.h"
#include "hsmenumodetransition.h"
#include "hsmenuentryremovedhandler.h"
#include "hsmainwindow.h"
#include "hsmenumodewrapper.h"


/*!
 Constructor.
 \param mainWindow main window wrapper object.
 \param parent Owner.
 */
HsBaseViewState::HsBaseViewState(HsMainWindow &mainWindow, QState *parent):
    QState(parent),
    mApplicationLaunchFailMessage(0),
    mModel(0),
    mContextMenu(0),
    mContextModelIndex(),
    mBackKeyAction(0),
    mMenuView(0),
    mMenuMode(0),
    mMainWindow(mainWindow)
{
    mBackKeyAction = new HbAction(Hb::BackNaviAction, this);
    mViewOptions = new HbMenu;
}

/*!
 Constructor.
 \param mainWindow main window wrapper object.
 \param menuMode menu mode object.
 \param parent Owner.
 */
HsBaseViewState::HsBaseViewState(HsMainWindow &mainWindow,
    HsMenuModeWrapper& menuMode,
    QState *parent):
    QState(parent),
    mApplicationLaunchFailMessage(0),
    mModel(0),
    mContextMenu(0),
    mContextModelIndex(),
    mBackKeyAction(0),
    mMenuView(0),
    mMenuMode(&menuMode),
    mMainWindow(mainWindow)
{
    mBackKeyAction = new HbAction(Hb::BackNaviAction, this);
    mViewOptions = new HbMenu;
}
/*!
 Initialize contained objects.
 \param menuViewBuilder object providing widgets for menu view.
 \param stateContext state context of the view the builder
     is to provide widgets for.
 */
void HsBaseViewState::initialize(HsMenuViewBuilder &menuViewBuilder,
    HsStateContext stateContext)
{
    mMenuView.reset(new HsMenuView(menuViewBuilder, stateContext, mMainWindow));
    mMenuView->view()->setNavigationAction(mBackKeyAction);
    mMenuView->view()->setMenu(mViewOptions);

    connect(this, SIGNAL(entered()),SLOT(stateEntered()));
    connect(this, SIGNAL(exited()),SLOT(stateExited()));
}

/*!
 Creates and open application launch fail message.
 \param errorCode eroor code to display.
 \param itemId id of the launched item.
 */
void HsBaseViewState::createApplicationLaunchFailMessage(int errorCode,
    int itemId)
{
    QString message;
    message.append(
        HbParameterLengthLimiter("txt_applib_info_launching_the_application_failed").arg(
            errorCode));

    // create and show message box
    mApplicationLaunchFailMessage = HsMenuDialogFactory().create(
            message, HsMenuDialogFactory::Close);

    QScopedPointer<HsMenuEntryRemovedHandler> entryObserver(
        new HsMenuEntryRemovedHandler(itemId, mApplicationLaunchFailMessage.data(), SLOT(close())));

    entryObserver.take()->setParent(mApplicationLaunchFailMessage.data());

    mApplicationLaunchFailMessage->open();
}

/*!
 Slot invoked when a state is entered.
 */
void HsBaseViewState::stateEntered()
{
    qDebug("HsBaseViewState::stateEntered()");
    HSMENUTEST_FUNC_ENTRY("HsBaseViewState::stateEntered");
    mMenuView->activate();
    connect(mMenuView.data(), SIGNAL(listViewChange()),
            this, SLOT(closeContextMenu()));
    HSMENUTEST_FUNC_EXIT("HsBaseViewState::stateEntered");
}

/*!
 Slot invoked when a state is exited.
 */
void HsBaseViewState::stateExited()
{
    HSMENUTEST_FUNC_ENTRY("HsBaseViewState::stateExited");

    mMenuView->hideSearchPanel();
    mMenuView->disconnect(this);

    mMenuView->inactivate();
    if (!mApplicationLaunchFailMessage.isNull()) {
        mApplicationLaunchFailMessage->close();
    }
    closeContextMenu();
    HSMENUTEST_FUNC_EXIT("HsBaseViewState::stateExited");
}

/*!
 Add mode entered.
 */
void HsBaseViewState::addModeEntered()
{
    mViewOptions = mMenuView->view()->takeMenu();
    connect(mMenuView.data(),
            SIGNAL(activated(QModelIndex)),
            SLOT(addActivated(QModelIndex)));
    connect(mMenuView.data(),
            SIGNAL(longPressed(HbAbstractViewItem *, QPointF)),
            SLOT(addLongPressed(HbAbstractViewItem *, QPointF)));
}

/*!
 Add mode exited.
 */
void HsBaseViewState::addModeExited()
{
    mMenuView->view()->setMenu(mViewOptions);
}

/*!
 Slot invoked when normal mode entered.
 */
void HsBaseViewState::normalModeEntered()
{
    setMenuOptions();
    connect(mMenuView.data(),
            SIGNAL(longPressed(HbAbstractViewItem *, QPointF)),
            SLOT(showContextMenu(HbAbstractViewItem *, QPointF)));
}

/*!
 Destructor.
 */
HsBaseViewState::~HsBaseViewState()
{
    delete mModel;
    mViewOptions = mMenuView->view()->takeMenu();
    delete mViewOptions;
}

/*!
 Slot connected to List widget in normal mode.
 \param index Model index of the activated item.
 */
void HsBaseViewState::launchItem(const QModelIndex &index)
{
    HSMENUTEST_FUNC_ENTRY("HsBaseViewState::launchItem");

    QSharedPointer<const CaEntry> entry = mModel->entry(index);
    if (!entry.isNull() && !(entry->flags() & UninstallEntryFlag)) {
        if (entry->entryTypeName() == Hs::widgetTypeName) {
            machine()->postEvent(HsMenuEventFactory::createPreviewHSWidgetEvent(entry->id(),
                entry->entryTypeName(), entry->attribute(Hs::widgetUriAttributeName),
                entry->attribute(Hs::widgetLibraryAttributeName)));
            HsMenuService::touch(entry->id());
        }
        else {
            int errCode = HsMenuService::executeAction(entry->id());
            if (errCode != 0) {
                createApplicationLaunchFailMessage(errCode, entry->id());
            }
        }
    }
    HSMENUTEST_FUNC_EXIT("HsBaseViewState::launchItem");
}

/*!
 Slot connected to List widget in normal mode.
 \param index Model index of the activated item.
 */
void HsBaseViewState::openCollection(const QModelIndex &index)
{
    HSMENUTEST_FUNC_ENTRY("HsBaseViewState::openCollection");
    QVariant data = mModel->data(index, CaItemModel::IdRole);
    int id = data.toInt();
    QString collectionType = mModel->data(
            index, CaItemModel::TypeRole).toString();
    qDebug("HsBaseViewState::openCollection - MCS ID: %d", data.toInt());

    machine()->postEvent(
            HsMenuEventFactory::createOpenCollectionFromAppLibraryEvent(
                    id, collectionType));
    HSMENUTEST_FUNC_EXIT("HsBaseViewState::openCollection");
}

/*!
 Slot connected to List widget in normal mode.
 \param index Model index of the activated item.
 */
void HsBaseViewState::showContextMenu(HbAbstractViewItem *item, const QPointF &coords)
{
    HSMENUTEST_FUNC_ENTRY("HsBaseViewState::showContextMenu");

    EntryFlags flags = item->modelIndex().data(
            CaItemModel::FlagsRole).value<EntryFlags> ();

    if (!(flags & UninstallEntryFlag)) {
        mContextMenu = new HbMenu;
        setContextMenuOptions(item,flags);
        mContextModelIndex = item->modelIndex();
        mContextMenu->setPreferredPos(coords);
        mContextMenu->setAttribute(Qt::WA_DeleteOnClose);
        mContextMenu->open(this, SLOT(contextMenuAction(HbAction*)));
    }
    HSMENUTEST_FUNC_EXIT("HsBaseViewState::showContextMenu");

}

/*!
 Open task switcher.
 \retval true if operation is successful.
 */
bool HsBaseViewState::openTaskSwitcher()
{
    return HsMenuService::launchTaskSwitcher();
}

/*!
 Menu softkey back action slot
 */
void HsBaseViewState::openAppLibrary()
{
    machine()->postEvent(HsMenuEventFactory::createOpenAppLibraryEvent());
}

/*!
 Triggers event so that a state adding to Home Screen is reached
 \param entryId of an item to be added to homescreen.
 \retval void
 */
void HsBaseViewState::addToHomeScreen(const int entryId)
{
    HSMENUTEST_FUNC_ENTRY("HsBaseViewState::addToHomeScreen");
    machine()->postEvent(
        HsMenuEventFactory::createAddToHomeScreenEvent(
            entryId, mMenuMode->getHsMenuMode(), mMenuMode->getHsToken()));
    HSMENUTEST_FUNC_EXIT("HsBaseViewState::addToHomeScreen");
}

/*!
 Check software updates.
 \retval 0 if operation is successful.
 */
int HsBaseViewState::checkSoftwareUpdates()
{
    int errCode = HsMenuService::launchSoftwareUpdate();
    if (errCode != 0){
        createApplicationLaunchFailMessage(errCode,0);
    }
    return errCode;
}

/*!
 close context menu
 */
void HsBaseViewState::closeContextMenu()
{
    if (mContextMenu) {
        mContextMenu->close();
    }    
}

/*!
 Handles context menu actions
 \param action action taken in context menu
 */
void HsBaseViewState::contextMenuAction(HbAction *action)
{
    Hs::HsContextAction command =
        static_cast<Hs::HsContextAction>(action->data().toInt());

    const int itemId = mContextModelIndex.data(CaItemModel::IdRole).toInt();

    switch (command) {
        case Hs::AddToHomeScreenContextAction:
            addToHomeScreen(itemId);
            break;
        case Hs::AddToCollectionFromApplicationsViewContextAction:
            // Addding a specific application to
            // an existing collection via item specific menu.
            machine()->postEvent(
                HsMenuEventFactory::createAddAppsFromApplicationsViewEvent(
                    Hs::NoHsSortAttribute, itemId));
            break;
        case Hs::AddToCollectionFromCollectionViewContextAction:
            machine()->postEvent(
                HsMenuEventFactory::createAddAppsFromCollectionViewEvent(
                    -1, itemId));
            break;
        case Hs::UninstallContextAction:
            machine()->postEvent(
                HsMenuEventFactory::createUninstallApplicationEvent(
                    itemId));
            break;
        case Hs::AppSettingContextAction:
            machine()->postEvent(
                HsMenuEventFactory::createAppSettingsViewEvent(itemId));
            break;
        case Hs::AppDetailsContextAction:
            machine()->postEvent(
                HsMenuEventFactory::createAppDetailsViewEvent(itemId));
            break;
        case Hs::OpenAppContextAction:
            launchItem(mContextModelIndex);
            break;
        case Hs::RenameCollectionContextAction:
            machine()->postEvent(
                HsMenuEventFactory::createRenameCollectionEvent(itemId));
            break;
        case Hs::DeleteCollectionContextAction:
             machine()->postEvent(
                HsMenuEventFactory::createDeleteCollectionEvent(itemId));
            break;
        case Hs::OpenCollectionContextAction:
            openCollection(mContextModelIndex);
            break;
        default:
            break;
    }
    
    HsMenuService::touch(itemId);
}

/*!
 Slot connected to List widget in add mode.
 \param index Model index of the activated item.
 */
void HsBaseViewState::addActivated(const QModelIndex &index)
{
    HSMENUTEST_FUNC_ENTRY("HsAllAppsState::addActivated");
    mMenuView->disconnect(this);
    const int itemId = index.data(CaItemModel::IdRole).toInt();
    addToHomeScreen(itemId);
    HsMenuService::touch(itemId);
    HSMENUTEST_FUNC_EXIT("HsAllAppsState::addActivated");
}

/*!
 Slot connected to List widget in add mode.
 Called when item long pressed.
 \param item View item.
 \param coords Press point coordinates.
 */
void HsBaseViewState::addLongPressed(HbAbstractViewItem *item,
                                    const QPointF &coords)
{
    Q_UNUSED(coords);
    HSMENUTEST_FUNC_ENTRY("HsAllAppsState::addLongPressed");
    addActivated(item->modelIndex());
    HSMENUTEST_FUNC_EXIT("HsAllAppsState::addLongPressed");
}

/*!
 Scrolls view to first item at top
 */
void HsBaseViewState::scrollToBeginning()
{
    mMenuView->listView()->scrollTo(
            mModel->index(0), HbAbstractItemView::PositionAtTop);
}

/*!
 Normal mode exited dummy implementation.
 */
void HsBaseViewState::normalModeExited()
{
}

/*!
 Defines transitions
 */
void HsBaseViewState::defineTransitions()
{
    QState *initialState = new QState(this);
    setInitialState(initialState);

    QState *addModeState = new QState(this);
    connect(addModeState, SIGNAL(entered()),SLOT(addModeEntered()));
    connect(addModeState, SIGNAL(exited()),SLOT(addModeExited()));

    QState *normalModeState = new QState(this);
    connect(normalModeState, SIGNAL(entered()),SLOT(normalModeEntered()));
    connect(normalModeState, SIGNAL(exited()),SLOT(normalModeExited()));

    initialState->addTransition(new HsMenuModeTransition(
            *mMenuMode, Hs::NormalHsMenuMode, normalModeState));
    initialState->addTransition(new HsMenuModeTransition(
            *mMenuMode, Hs::AddHsMenuMode, addModeState));
}

