/*
 * 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:
 *
 */

// INCLUDES
#include <HbTextItem>
#include <HbIconItem>
#include <HbMainWindow>
#include <HbDeviceProfile>
#include <QImageReader>
#include <QFileInfo>
#include <MsgMediaResolver.h>
#include <MsgImageInfo.h>
#include <HbIconAnimationManager>
#include <HbIconAnimator>
#include <QGraphicsLinearLayout>
#include <HbNotificationDialog>

#include <xqaiwrequest.h>
#include <xqrequestinfo.h>
#include <xqsharablefile.h>
#include <xqappmgr.h>
#include <xqconversions.h>
#include <hbmessagebox.h>

// USER INCLUDES
#include "msgunieditorbody.h"
#include "UniEditorGenUtils.h"
#include "msgunieditormonitor.h"

#include "mmsconformancecheck.h"
#include "msgunieditorpixmapwidget.h"
#include "msgunieditoraudiowidget.h"
#include "msgunieditorview.h"

// Constants
const int BYTES_TO_KBYTES_FACTOR = 1024; 

//Localized Constants for item specific menu
#define LOC_UNABLE_TO_ATTACH_ITEM hbTrId("txt_messaging_dpopinfo_unable_to_attach_item_avai")
#define LOC_PROCESSING hbTrId("txt_messaging_formlabel_loading")
#define LOC_ATTACHED_PHOTO_SIZE hbTrId("txt_messaging_dpopinfo_attached_photo_size_is_l1")

const QString ANIMATION_ICON("qtg_anim_loading");
const QString ANIMATION_FILE("qtg_anim_loading.axml");
// LOCAL FUNCTIONS

//---------------------------------------------------------------
// showInsertFailureNote
// @return fullPath of unified editor's temporary dir
//---------------------------------------------------------------
void showInsertFailureNote()
{
    int availableSize =
        (MsgUnifiedEditorMonitor::maxMmsSize() - MsgUnifiedEditorMonitor::messageSize())
        /BYTES_TO_KBYTES_FACTOR;
    QString displayStr = QString(LOC_UNABLE_TO_ATTACH_ITEM)
                .arg(availableSize);

    HbMessageBox::information(displayStr, 0, 0, HbMessageBox::Ok);
}


MsgUnifiedEditorBody::MsgUnifiedEditorBody( QGraphicsItem *parent ) :
MsgUnifiedEditorBaseWidget(parent),
mHasImage(false),
mHasAudio(false),
mPixmapItem(0),
mAudioItem(0),
mImageSize(0),
mAudioSize(0),
mProcessImageOperation(0),
mMediaResolver(0),
mImageInfo(0),
mProcessingWidget(0),
mDraftMessage(false)
{
    this->setObjectName("body");
    mMmsConformanceCheck = new MmsConformanceCheck;    
}

MsgUnifiedEditorBody::~MsgUnifiedEditorBody()
{
    delete mMmsConformanceCheck;
    delete mProcessImageOperation;
    delete mMediaResolver;
    delete mImageInfo;
}

void MsgUnifiedEditorBody::setImage(const QString& imagefile, bool draftMessage)
    {
    
   // do nothing if filepath is empty
    if (imagefile.isEmpty())
        {
        return;
        }
    
    //disable image option in menu.
    emit enableMenuAction(PHOTO,false);

    mDraftMessage = draftMessage;
    if (!mImageInfo)
        {
        setImage(true);

        mImageFile = imagefile;
        if (mPixmapItem)
            {
            mPixmapItem->setParent(NULL);
            delete mPixmapItem;
            mPixmapItem = NULL;
            mImageSize = 0;
            }

        int error = KErrNone;
        if (!mDraftMessage)
            {
        // if image is in draft, no need to resize it because it is resized already
            if (!mProcessImageOperation)
                {
                TRAP(error,mProcessImageOperation =
                        CUniEditorProcessImageOperation::NewL(*this));
                }
            if (!mMediaResolver && error == KErrNone)
                {
                TRAP(error,mMediaResolver = CMsgMediaResolver::NewL());
                }

            if (error == KErrNone)
                {
                mMediaResolver->SetCharacterSetRecognition(EFalse);
                HBufC *name = XQConversions::qStringToS60Desc(imagefile);
                RFile file;
                TRAP(error, file = mMediaResolver->FileHandleL(*name));
                if (error == KErrNone)
                    {
                    TRAP(error,mImageInfo = static_cast<CMsgImageInfo*>
                            (mMediaResolver->CreateMediaInfoL(file)));
                    if (error == KErrNone)
                        {
                        TRAP(error, mMediaResolver->ParseInfoDetailsL(
                                        mImageInfo, file));
                        }
                    file.Close();
                    }
                delete name;
                }
            }
        if (error == KErrNone && !mDraftMessage)
            {
            mSavedImageFile = imagefile;
            startResizeAnimation();
            
            // image resize is started. set the image resize flag.
            emit contentsChanged(true);
            
            mProcessImageOperation->Process(mImageInfo);
            }
        else
            {
            if (mImageInfo)
                {
                delete mImageInfo;
                mImageInfo = NULL;
                }
            mSavedImageFile.clear();
            handleSetImage();
            }

        }
    }

void MsgUnifiedEditorBody::handleSetImage()
{   
    //check for insert conformance
    if(EInsertSuccess != mMmsConformanceCheck->checkModeForInsert(mImageFile))
    {
        //enable image option in menu as insertion failed.
        emit enableMenuAction(PHOTO,true);
        return;
    }
    
    int msgSize = MsgUnifiedEditorMonitor::messageSize();
    QFileInfo fileinfo(mImageFile);
    int imageSize = fileinfo.size() + KEstimatedMimeHeaderSize;
    if ( (imageSize + msgSize) <= MsgUnifiedEditorMonitor::maxMmsSize())
    {
        mImageSize = imageSize;
    }
    else
    {
        mImageFile.clear();
        setImage(false);
        //Show appropriate note and leave
        showInsertFailureNote();
        
        //enable image option in menu as insertion failed.
        emit enableMenuAction(PHOTO,true);
        
        return;
    }

    mPixmapItem = new MsgUnifiedEditorPixmapWidget(this);
    mPixmapItem->hide();
    HbStyle::setItemName(mPixmapItem, "pixmap");
    mPixmapItem->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
    mPixmapItem->populate(mImageFile);
    connect(mPixmapItem,SIGNAL(remove()),this,SLOT(removeMedia()));
    
    // repolish the body widget
    this->repolish();

    // emit signal to indicate addition of image
    emit contentsChanged(bodySize());    
}

void MsgUnifiedEditorBody::setAudio(const QString& audiofile)
{
    // do nothing if filepath is empty
    if(audiofile.isEmpty())
    {
        return;
    }

    //check for insert conformance
    if(EInsertSuccess != mMmsConformanceCheck->checkModeForInsert(audiofile))
        return;

    setAudio(true);
    mAudioFile = audiofile;
    if(mAudioItem)
    {
        mAudioItem->setParent(NULL);
        delete mAudioItem;
        mAudioItem = NULL;
        mAudioSize = 0;
    }

    int msgSize = MsgUnifiedEditorMonitor::messageSize();
    QFileInfo fileinfo(mAudioFile);
    int audioSize = fileinfo.size() + KEstimatedMimeHeaderSize;
    if((audioSize + msgSize) <= MsgUnifiedEditorMonitor::maxMmsSize() )
    {
    	mAudioSize = audioSize;
    }
    else
    {
    	mAudioFile.clear();
    	setAudio(false);
    	//Show appropriate note and leave
    	showInsertFailureNote();
    	return;
    }    

    mAudioItem = new MsgUniFiedEditorAudioWidget(this);
    mAudioItem->hide();
    HbStyle::setItemName(mAudioItem,"audioItem");
    mAudioItem->populate(mAudioFile);
    connect(mAudioItem,SIGNAL(remove()),this,SLOT(removeMedia()));

    // repolish the body widget
    this->repolish();

    // emit signal to indicate addition of audio
    emit contentsChanged(bodySize());
    
    //disable sound option in menu.
    emit enableMenuAction(SOUND,false);
}

const QStringList MsgUnifiedEditorBody::mediaContent()
{
    QStringList mediaFiles;
    // Pick mImageFile only if mSavedImageFile is empty 
    // as it means we are not in middle of resizing
    if (mHasImage && mSavedImageFile.isEmpty()) 
        mediaFiles << mImageFile;
    if(mHasAudio)
        mediaFiles << mAudioFile;

    return mediaFiles;
}

QSizeF MsgUnifiedEditorBody::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    QSizeF szHint = HbWidget::sizeHint(which,constraint);

    HbMainWindow* mMainWindow = this->mainWindow();    
    if(!mMainWindow)
    {
        return szHint;
    }

    qreal leftMargin = 0.0;
    qreal rightMargin = 0.0;
    qreal chromeHeight = 0.0;
    qreal toolbarHeight = 0.0;
    qreal bodyItemSpacing = 0.0;
    
    style()->parameter("hb-param-margin-gene-left",leftMargin);
    style()->parameter("hb-param-margin-gene-right",rightMargin);
    style()->parameter("hb-param-widget-chrome-height",chromeHeight);
    style()->parameter("hb-param-widget-toolbar-height",toolbarHeight);
    style()->parameter("hb-param-margin-gene-middle-vertical",bodyItemSpacing);

    HbDeviceProfile prf = HbDeviceProfile::profile(mMainWindow);
    qreal unt = prf.unitValue();

    qreal maxWidth = mMainWindow->width()-leftMargin-rightMargin;
    qreal maxHeight = mMainWindow->height()-chromeHeight-toolbarHeight;

    szHint.setHeight(0);
    
    // add space for audio
    if(mAudioItem)
    {
		if(mMainWindow->orientation() == Qt::Horizontal)
		{
			mAudioItem->setStretched(true);
		}
		else
		{
			mAudioItem->setStretched(false);
		}
        QSizeF audioSize = mAudioItem->effectiveSizeHint(which, constraint);
        szHint.rheight() += (audioSize.height() + bodyItemSpacing);
        mAudioItem->show();
    }
    
    if(mPixmapItem || mProcessingWidget)
        {
        QSizeF imageSize(0.0,0.0);
        QSizeF defaultImageSize(QImageReader(mImageFile).size());

        if(!defaultImageSize.isEmpty())
            {
            imageSize.setWidth(maxWidth);
            if(mMainWindow->orientation() == Qt::Vertical)
            {
                szHint.rheight() += bodyItemSpacing;
            }

            qreal newHeight = 0.0;
            if(defaultImageSize.width() <= imageSize.width())
            {
                // resize not needed
                newHeight = qMin(defaultImageSize.height(), maxHeight);
                imageSize.setHeight(newHeight);
            }
            else
            {
                // keep aspect-ratio and resize
                newHeight = imageSize.width()*(defaultImageSize.height()/defaultImageSize.width());
                newHeight = qMin(newHeight,maxHeight);
                imageSize.setHeight(newHeight);
            }

            if(newHeight == maxHeight)
            {
                qreal newWidth = defaultImageSize.width()*newHeight/defaultImageSize.height();
                imageSize.setWidth(newWidth);
            }

            if(mPixmapItem)
            {
            mPixmapItem->setPreferredSize(imageSize);
            mPixmapItem->setSize(imageSize);
            mPixmapItem->show();
            }
            
            if(mProcessingWidget)
            {
                imageSize.setHeight(mProcessingWidget->preferredHeight());
                mProcessingWidget->setPreferredSize(imageSize);
                mProcessingWidget->show();
            }
            szHint.rheight() += imageSize.height();
        }
    }
    
    szHint.rheight() += bodyItemSpacing;
    return szHint;
}

void MsgUnifiedEditorBody::removeMedia()
{
    QObject* senderObject = sender();
    
    MsgUnifiedEditorPixmapWidget* pixmap = 
        qobject_cast<MsgUnifiedEditorPixmapWidget*>(senderObject);

    MsgUniFiedEditorAudioWidget* audio = 
        qobject_cast<MsgUniFiedEditorAudioWidget*>(senderObject);
    
    if(pixmap) //remove image
    {
        mImageFile.clear();
        if(mPixmapItem)
        {
            mPixmapItem->setParent(NULL);
            delete mPixmapItem;
            mPixmapItem = NULL;
        }
        setImage(false);
        mImageSize = 0;
        
        //enable photo option in menu.
        emit enableMenuAction(PHOTO,true);
        
    }
    else if(audio)//remove audio item
        {
            mAudioFile.clear();
            if(mAudioItem)
            {
                mAudioItem->setParent(NULL);
                delete mAudioItem;
                mAudioItem = NULL;
            }
            setAudio(false);
            mAudioSize = 0;
            
            //enable sound option in menu.
            emit enableMenuAction(SOUND,true);
        }

    this->repolish();

	emit contentsChanged(bodySize());
}

bool MsgUnifiedEditorBody::hasImage()
{
    return mHasImage;
}

void MsgUnifiedEditorBody::setImage(bool image)
{
    mHasImage = image;
}

bool MsgUnifiedEditorBody::hasAudio()
{
    return mHasAudio;
}

void MsgUnifiedEditorBody::setAudio(bool audio)
{
    mHasAudio = audio;
}

int MsgUnifiedEditorBody::bodySize()
{
    return mImageSize + mAudioSize;
}

void MsgUnifiedEditorBody::EditorOperationEvent(
    TUniEditorProcessImageOperationEvent aEvent, TFileName& aFileName)
{
    delete mImageInfo;
    mImageInfo = NULL;

    if (aEvent == EUniEditorProcessImageOperationComplete && 
            aFileName.Length() > 0)
    {
        mImageFile = XQConversions::s60DescToQString(aFileName);
        
        QSize modifiedSize(QImageReader(mImageFile).size());
        QString information = LOC_ATTACHED_PHOTO_SIZE.arg(modifiedSize.width()).arg(modifiedSize.height());
        HbNotificationDialog::launchDialog(information);        
    }
    else
    {
        mImageFile = mSavedImageFile;
    }
    mSavedImageFile.clear();

   // image resize is complete. reset the image resize flag
    emit contentsChanged(false);
    
    //handle the processed image from ProcessImage Operation
    handleSetImage();
    
    stopResizeAnimation();
}

void MsgUnifiedEditorBody::startResizeAnimation()
{
    QGraphicsLinearLayout* processingLayout = new QGraphicsLinearLayout(Qt::Vertical);
    
    mProcessingWidget = new HbWidget(this);
    HbStyle::setItemName(mProcessingWidget,"pixmap"); 
    mProcessingWidget->hide();
    mProcessingWidget->setLayout(processingLayout);
    
    HbTextItem* processingText = new HbTextItem(LOC_PROCESSING,mProcessingWidget);
    processingText->setFontSpec(HbFontSpec(HbFontSpec::Secondary));
    processingText->setAlignment(Qt::AlignCenter);
    processingLayout->addItem(processingText);
    
    HbIconItem* animationItem = new HbIconItem(ANIMATION_ICON,mProcessingWidget);
    animationItem->setAlignment(Qt::AlignHCenter);
    processingLayout->addItem(animationItem);
    
    HbIconAnimator& iconAnimator = animationItem->animator();
    HbIconAnimationManager* iconAnimationManager = HbIconAnimationManager::global();
    iconAnimationManager->addDefinitionFile(ANIMATION_FILE);
    
    iconAnimator.startAnimation();
    
    this->repolish();    
}

void MsgUnifiedEditorBody::stopResizeAnimation()
{
    if(mProcessingWidget)
    {
        delete mProcessingWidget;
        mProcessingWidget = NULL;
    }
	
}

//---------------------------------------------------------------
// MsgUnifiedEditorBody :: removeMediaContent
// @see header file
//---------------------------------------------------------------
void MsgUnifiedEditorBody::removeMediaContent(QString fileName)
{
    if(!(mImageFile.compare(fileName))) //remove image
    {
        mImageFile.clear();
        if(mPixmapItem)
        {
            mPixmapItem->setParent(NULL);
            delete mPixmapItem;
            mPixmapItem = NULL;
        }
        setImage(false);
        mImageSize = 0;
    }
    else if(!(mAudioFile.compare(fileName)))//remove audio item
    {
        mAudioFile.clear();
        if(mAudioItem)
        {
            mAudioItem->setParent(NULL);
            delete mAudioItem;
            mAudioItem = NULL;
        }
        setAudio(false);
        mAudioSize = 0;
    }

    this->repolish();

    emit contentsChanged(bodySize());
}
// EOF
