/****************************************************************************
**
** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (developer.feedback@nokia.com)
**
** This file is part of the HbCore module of the UI Extensions for Mobile.
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at developer.feedback@nokia.com.
**
****************************************************************************/

#include "hbthetestwidget_p.h"
#include "hbinstance.h"
#include "hbnamespace_p.h"
#include "hbapplication.h"
#include "hbtoolbutton_p.h"
#include "hbstyleoptiontoolbutton_p.h"
#include "hbcolorscheme.h"
#include "hbtextitem.h"
#include "hbpopup.h"
#include "hbdialog.h"
#include "hbthemecommon_p.h"
#include "hbthemeclient_p.h"
#include "hbstyle_p.h"

#ifdef Q_OS_SYMBIAN
#include <eikenv.h>
#include <apgtask.h>                // TApaTaskList, TApaTask
#endif

#include <QGraphicsSceneMouseEvent>
#include <QGraphicsGridLayout>
#include <QGraphicsLinearLayout>
#include <QGraphicsWidget>
#include <QTextStream>
#include <QFile>
#include <QDir>
#include <QTimer>
#include <QProcess>
#include <hbaction.h>

#include <QDebug> // for qWarning

#ifdef HB_TEXT_MEASUREMENT_UTILITY
#include "hbtextmeasurementutility_r.h"
#endif //HB_TEXT_MEASUREMENT_UTILITY

//#ifdef Q_OS_SYMBIAN
//#include <coemain.h>
//#include <fbs.h>
//#endif

const int KWidth = 140; // container size, button width is KWidth/2
const int KHeight = 140; // container size, button height is KHeight/2
// how much must button be dragged before it is actually moved
const int KThreshold = 16;

const QString KDriveFPath("F:\\data\\log\\");
const QString KDriveEPath("E:\\data\\log\\");
const QString KDriveCPath("C:\\data\\log\\");
const QString KTheAppLaunchConfigureFile("app_launch_config.txt");

HbTheTestButton::HbTheTestButton(QGraphicsItem *parent)
: HbToolButton(parent),
  mPressedDown(false)
{
    setAttribute(Hb::InteractionDisabled); // no feedback from test button
    mPosition = scenePos();
    mScreenSize = HbDeviceProfile::profile(this).logicalSize();
}

HbTheTestButton::~HbTheTestButton()
{
}

QSizeF HbTheTestButton::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    switch(which){
    case Qt::MinimumSize: //fallthrough
    case Qt::MaximumSize: //fallthrough
        return QSizeF(KWidth/2, KHeight/2);
    default:
        return HbAbstractButton::sizeHint( which, constraint );
    }
}

/*!
    \reimp
    Removed tooltip support.
 */
void HbTheTestButton::updatePrimitives()
{
    HbToolButtonPrivate *d = static_cast<HbToolButtonPrivate *>(HbToolButton::d_ptr);

    HbStyleOptionToolButton option;
    if (d->action) {
        setCheckable(d->action->isCheckable());
        setChecked(d->action->isChecked());
        setEnabled(d->action->isEnabled());
    }

    initStyleOption(&option);
    if (d->frameItem) {
        HbStylePrivate::updatePrimitive(d->frameItem, HbStylePrivate::P_ToolButton_frame, &option);
    }
    if (d->textItem) {
        HbStylePrivate::updatePrimitive(d->textItem, HbStylePrivate::P_ToolButton_text, &option);
    }
    if (d->iconItem) {
        HbStylePrivate::updatePrimitive(d->iconItem, HbStylePrivate::P_ToolButton_icon, &option);
    }
}

/*!
  reimp
*/
void HbTheTestButton::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    HbToolButton::mousePressEvent(event);
    mPressedDown = true;
    mMoved = false;
    mPressedPos = event->scenePos();
    mPosition = scenePos() - pos();
    event->accept();
}

/*!
  reimp
*/
void HbTheTestButton::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    if (!mMoved) {
        HbToolButton::mouseReleaseEvent(event);
    }
    mMoved = false;
    mPressedDown = false;
    event->accept();
}

/*!
  reimp

*/
void HbTheTestButton::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    HbToolButton::mouseMoveEvent(event);
    QPointF moved = mPressedPos - event->scenePos();
    if (mMoved || (mPressedDown && ((qAbs(moved.x()) > KThreshold) ||
                                   (qAbs(moved.y()) > KThreshold)))) {
        QPointF newPosition = mPosition - moved;
        if ((newPosition.x() + pos().x()) < 0) {
            newPosition.setX(0 - pos().x());
        }
        if ((newPosition.y() + pos().y()) < 0) {
            newPosition.setY(0 - pos().y());
        }

        if (newPosition.x() > (mScreenSize.width() - KWidth/2 - pos().x())) {
            newPosition.setX(mScreenSize.width() - KWidth/2 - pos().x());
        }
        if (newPosition.y() > (mScreenSize.height() - KHeight/2 - pos().y())) {
            newPosition.setY(mScreenSize.height() - KHeight/2 - pos().y());
        }
        HbTheTestWidget *parentWidget = qgraphicsitem_cast<HbTheTestWidget*>(parentItem());
        if (parentWidget) {
            mMoved = true;
            parentWidget->setPos(newPosition);
        }
        setDown(false);
    }
}




class HbTheTestWidgetPrivate
{
public:
    HbMainWindow *mMainWindow;
    HbTheTestButton *mButton1;
    HbTheTestButton *mButton2;
    HbTheTestButton *mButton3;
    HbTheTestButton *mButton4;
    QGraphicsGridLayout *mLayout;
#ifdef HB_TEXT_MEASUREMENT_UTILITY
    HbDeviceProfile mLocalizationMetricsProfile;
#endif
};

/*!
    \class HbTheTestWidget
    \internal
    \proto
*/
HbTheTestWidget::HbTheTestWidget(HbMainWindow *mainWindow, QGraphicsItem *parent)
: HbWidget(parent)
{
    d = new HbTheTestWidgetPrivate;
    d->mMainWindow = mainWindow;

    d->mLayout = new QGraphicsGridLayout();
    d->mLayout->setContentsMargins( qreal(0.0), qreal(0.0), qreal(0.0), qreal(0.0) );
    d->mLayout->setSpacing(0.0);
    setLayout(d->mLayout);

    HbAction *action1 = new HbAction(QString("1"),this);
    d->mButton1 = new HbTheTestButton(this);
    d->mButton1->setAction(action1);

    HbAction *action2 = new HbAction(QString("2"),this);
    d->mButton2 = new HbTheTestButton(this);
    d->mButton2->setAction(action2);

    HbAction *action3 = new HbAction(QString("3"),this);
    d->mButton3 = new HbTheTestButton(this);
    d->mButton3->setAction(action3);

    HbAction *action4 = new HbAction(QString("4"),this);
    d->mButton4 = new HbTheTestButton(this);
    d->mButton4->setAction(action4);

    d->mLayout->addItem(d->mButton1, 0, 0);
    d->mLayout->addItem(d->mButton2, 0, 1);
    d->mLayout->addItem(d->mButton3, 1, 0);
    d->mLayout->addItem(d->mButton4, 1, 1);

    QSize screenSize = HbDeviceProfile::profile(this).logicalSize();
    setPos((screenSize.width()-KWidth)/2,(screenSize.height()-KHeight)/2);

    QObject::connect(mainWindow, SIGNAL(orientationChanged(Qt::Orientation)),
        this, SLOT(orientationChanged(Qt::Orientation)));
}


HbTheTestWidget::~HbTheTestWidget()
{
    delete d;
}

void HbTheTestWidget::orientationChanged(Qt::Orientation newOrientation)
{
    Q_UNUSED(newOrientation)
    QSize screenSize = HbDeviceProfile::profile(this).logicalSize();
    setPos((screenSize.width()-KWidth)/2,(screenSize.height()-KHeight)/2);
    d->mButton1->mScreenSize = screenSize;
    d->mButton2->mScreenSize = screenSize;
    d->mButton3->mScreenSize = screenSize;
    d->mButton4->mScreenSize = screenSize;
}

QSizeF HbTheTestWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    switch(which){
    case Qt::MinimumSize: //fallthrough
    case Qt::MaximumSize: //fallthrough
        return QSizeF(KWidth, KHeight);
    default:
        return HbWidget::sizeHint( which, constraint );
    }
}

HbTheTestButton *HbTheTestWidget::button1()
{
    if (d) {
        return d->mButton1;
    }
    return 0;
}

HbTheTestButton *HbTheTestWidget::button2()
{
    if (d) {
        return d->mButton2;
    }
    return 0;
}

HbTheTestButton *HbTheTestWidget::button3()
{
    if (d) {
        return d->mButton3;
    }
    return 0;
}

HbTheTestButton *HbTheTestWidget::button4()
{
    if (d) {
        return d->mButton4;
    }
    return 0;
}

// slots that can be used in test buttons start here

void HbTheTestWidget::textLayoutMeasure()
{
#ifdef HB_TEXT_MEASUREMENT_UTILITY
    HbTextMeasurementUtility *measureUtility = HbTextMeasurementUtility::instance();
    if ( measureUtility->locTestMode() ) {
        HbDeviceProfile profile = HbDeviceProfile::profile(d->mMainWindow);
        if (profile.name() != d->mLocalizationMetricsProfile.name()) {
            measureUtility->reset();
            d->mLocalizationMetricsProfile = profile;
        }

        QFileInfo info(QCoreApplication::applicationFilePath());
        // Existing result file is updated. Previous data is read to memory first.  
        measureUtility->readReport(profile, info.baseName());
        measureUtility->measureItems();
        measureUtility->writeReport(profile, info.baseName());
    } else {
        showWarning("Localization metrics run-time flag disabled!");
    }
#else
    showWarning("Localization metrics compile-time flag disabled!");
#endif //HB_TEXT_MEASUREMENT_UTILITY
}

void HbTheTestWidget::textLayoutWriteReport()
{
#ifdef HB_TEXT_MEASUREMENT_UTILITY
    // For compatibility.
    textLayoutMeasure();
#else
    showWarning("Localization metrics compile-time flag disabled!");
#endif //HB_TEXT_MEASUREMENT_UTILITY
}

void HbTheTestWidget::toggleOrientation()
{
    if (d->mMainWindow->orientation() == Qt::Horizontal)
        d->mMainWindow->setOrientation(Qt::Vertical);
    else 
        d->mMainWindow->setOrientation(Qt::Horizontal);
}

void HbTheTestWidget::toggleMirroring()
{
    Qt::LayoutDirection dir = d->mMainWindow->layoutDirection();
    d->mMainWindow->setLayoutDirection(dir == Qt::LeftToRight ? Qt::RightToLeft : Qt::LeftToRight);
}

void HbTheTestWidget::setApplicationBackground()
{
#ifdef Q_OS_SYMBIAN
    TApaTask task(CEikonEnv::Static()->WsSession());
    task.SetWgId(CEikonEnv::Static()->RootWin().Identifier());
    task.SendToBackground();
#endif
}

void HbTheTestWidget::showThemeServerMemoryInfo()
{
#ifdef Q_OS_SYMBIAN
    HbDialog *dialog = new HbDialog();
    dialog->setAttribute(Qt::WA_DeleteOnClose);

    dialog->setModal(false);
    dialog->setBackgroundFaded(false);
    dialog->setDismissPolicy(HbPopup::NoDismiss);
    dialog->setTimeout(HbPopup::StandardTimeout);   
    dialog->setPreferredPos(QPointF(10,10));
    
    int freeSharedMemory = HbThemeClient::global()->freeSharedMemory();
    int allocatedSharedMemory = HbThemeClient::global()->allocatedSharedMemory();
    int allocatedHeapMemory = HbThemeClient::global()->allocatedHeapMemory();
    QString message("Free shared mem: ");
    message += QString::number(freeSharedMemory / 1024);
    message += " kB \nAllocated shared mem: ";
    message += QString::number(allocatedSharedMemory / 1024);
    message += " kB \nAllocated heap: ";
    message += QString::number(allocatedHeapMemory / 1024);
    message += " kB \n";
    HbTextItem *textItem = new HbTextItem(message);
    textItem->setTextColor(HbColorScheme::color("qtc_default_main_pane_normal"));

    QSizeF popupSize(50,50);
    dialog->setMinimumSize(popupSize); // needed
    
    dialog->setContentsMargins(5,15,5,15);
    dialog->setContentWidget(textItem);

    dialog->show();
#endif
}

void HbTheTestWidget::createSharedMemoryReport() const
{
#ifdef Q_OS_SYMBIAN
#ifdef HB_THEME_SERVER_MEMORY_REPORT
    HbThemeClient::global()->createMemoryReport();
#endif
#endif // Q_OS_SYMBIAN
}

void HbTheTestWidget::launchThemeChanger()
{
    QProcess::startDetached("hbthemechanger.exe");
}

void HbTheTestWidget::launchApplications()
{
    // Find config file
    QString filePath = findAppLaunchConfigFile();

    QStringList commandLines;

    if (!filePath.isEmpty()) {
        // Try to read file
        QFile file(filePath);
        if (file.open(QIODevice::ReadOnly)) {
            QString line;

            while (!file.atEnd()) {
                QByteArray dirtyLine = file.readLine();
                line = QString(dirtyLine).trimmed();
                // Skip empty lines and comment lines
                if (line.isEmpty() || line.at(0) == '#') {
                    continue;
                }
                commandLines.append(line);
            }
        }
    }

    for (int i=0; i<commandLines.count(); i++) {
        int index = 0;
        // Parse program name and arguments from the command line
        QString cmdLine = commandLines.at(i);
        QStringList args;
        
        while (index < cmdLine.count()) {
            int startIndex = index;
            // Find empty space
            while (index < cmdLine.count() && !cmdLine[index].isSpace()) index++;
            args.append(cmdLine.mid(startIndex, index-startIndex));
            // Find non-empty space
            while (index < cmdLine.count() && cmdLine[index].isSpace()) index++;
        }

        if (!args.count()) {
            continue;
        }

        QString program = args.at(0);
        args.removeFirst();

        QProcess::startDetached(program, args);
    }
}

void HbTheTestWidget::screenCapture()
{
    setVisible(false);
    QTimer::singleShot(1000, this, SLOT(doScreenCapture()));
}

void HbTheTestWidget::doScreenCapture()
{
#if defined (Q_OS_WIN32)
    QString filePath("c:\\");
    filePath = QDir::toNativeSeparators(filePath);
#elif defined (Q_OS_SYMBIAN)
    QString filePath("f:\\");
    filePath = QDir::toNativeSeparators(filePath);
    if (!QDir(filePath).exists()) {
        filePath = "e:\\";
        filePath = QDir::toNativeSeparators(filePath);
        if (!QDir(filePath).exists()) {
            filePath = "c:\\"; // this should always exist
            filePath = QDir::toNativeSeparators(filePath);
        }
    }
#elif defined (Q_OS_UNIX)
    QString filePath(QDir::tempPath());
    filePath.append(QDir::separator());
#endif

    filePath.append("data");
    filePath.append(QDir::separator());
    filePath.append("hb_screenshots");

    QDir dir(filePath);
    if (!dir.exists()) {
        dir.mkpath(filePath);
    }

    filePath.append(QDir::separator());
    if (!HbApplication::applicationName().isEmpty()) {
        filePath.append(HbApplication::applicationName());
    } else {
        filePath.append("unknown_application");
    }
    filePath.append(".png");

    QPixmap screenPixmap = QPixmap::grabWindow(
        QApplication::activeWindow()->winId()); //krazy:exclude=qclasses

    QString format = "png";
    screenPixmap.save(filePath.toLatin1(), format.toLatin1());
    setVisible(true);
}

void HbTheTestWidget::showWarning(QString text)
{
    HbTextItem *textItem = new HbTextItem(text);
    textItem->setAlignment(Qt::AlignHCenter);
    textItem->setFontSpec(HbFontSpec(HbFontSpec::Secondary));
    textItem->setTextColor(HbColorScheme::color("qtc_popup_normal"));

    HbDialog *dialog = new HbDialog();
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->setContentWidget(textItem);
    dialog->setContentsMargins(5,15,5,15);
    dialog->show();
}

QString HbTheTestWidget::findAppLaunchConfigFile()
{
    QString filePath;

#if defined (Q_OS_SYMBIAN)
    if (QFile::exists(KDriveFPath + KTheAppLaunchConfigureFile)) {
        filePath = KDriveFPath + KTheAppLaunchConfigureFile;
    } else if (QFile::exists(KDriveEPath + KTheAppLaunchConfigureFile)) {
        filePath = KDriveEPath + KTheAppLaunchConfigureFile;
    } else if (QFile::exists(KDriveCPath + KTheAppLaunchConfigureFile)) {
        filePath = KDriveCPath + KTheAppLaunchConfigureFile;
    }
#elif defined (Q_OS_WIN32)
    if (QFile::exists(KDriveCPath + KTheAppLaunchConfigureFile)) {
        filePath = KDriveCPath + KTheAppLaunchConfigureFile;
    }
    // only Symbian and Windows are supported
#endif

    return filePath;
}

