/*
 * 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: manages scrollable portion of view.
 *
 */

#include "msgunieditorscrollarea.h"

#include <QGraphicsLinearLayout>
#include <HbGroupBox>
#include <HbAction>
#include <QInputContext>
#include <qfile.h>
#include <qapplication.h>
#include <xqconversions.h>
#include <commonphoneparser.h> 
#include <HbNotificationDialog>
#include <hbmainwindow.h>

#include "msgunieditoraddress.h"
#include "msgunieditorsubject.h"
#include "msgunieditorbody.h"
#include "msgunieditorsubject.h"
#include "msgunieditorbody.h"
#include "msgunieditormonitor.h"
#include "msgunieditorattachmentcontainer.h"
#include "UniEditorGenUtils.h"
#include "msgunieditorview.h"

// LOCALIZED CONSTANTS
//To,Cc.Bcc
#define LOC_TO  hbTrId("txt_messaging_formlabel_to")
#define LOC_CC  hbTrId("txt_messaging_formlabel_cc")
#define LOC_BCC hbTrId("txt_messaging_formlabel_bcc")
//group box
#define LOC_OTHER_RECIPIENTS(n) hbTrId("txt_messaging_title_ln_other_recipients",n)
#define LOC_OTHER_RECIPIENTS_EXPAND hbTrId("txt_messaging_title_other_recipients")

// attachment addition failure note
#define LOC_UNABLE_TO_ADD_ATTACHMENTS hbTrId("txt_messaging_dpopinfo_unable_to_attach_l1_of_l2")

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::MsgUnifiedEditorScrollArea
//
//---------------------------------------------------------------
MsgUnifiedEditorScrollArea::MsgUnifiedEditorScrollArea(MsgUnifiedEditorMonitor* msgMonitor,QGraphicsItem *parent) :
HbScrollArea(parent),
mMsgMonitor(msgMonitor),
mMainLayout(0),
mToField(0),
mCcField(0),
mBccField(0),
mSubjectField(0),
mBody(0),
mAttachmentContainer(0),
mEnableScrolling(true)
{
    init();
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::~MsgUnifiedEditorScrollArea
//
//---------------------------------------------------------------
MsgUnifiedEditorScrollArea::~MsgUnifiedEditorScrollArea()
{
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::init
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::init()
{
    HbWidget* contentWidget = new HbWidget(this);
    this->setContentWidget(contentWidget);

    mMainLayout = new QGraphicsLinearLayout(Qt::Vertical, contentWidget);
    qreal vTopSpacing = 0.0;
    qreal vItemSpacing = 0.0;
    style()->parameter("hb-param-margin-gene-top",vTopSpacing);    
    style()->parameter("hb-param-margin-gene-middle-vertical",vItemSpacing);
    
    mMainLayout->setContentsMargins(0,0,0,0);
    mMainLayout->setSpacing(vItemSpacing);

    mToField = new MsgUnifiedEditorAddress( LOC_TO, this ); 
    mToField->setObjectName("to");
    
    mBody =  new MsgUnifiedEditorBody(this);
        
    mMainLayout->addItem(mToField);
    mMainLayout->addItem(mBody);
    mMainLayout->addStretch(2);
 
    connect(mToField, SIGNAL(contentsChanged(const QVariant&)),
            mMsgMonitor, SLOT(handleContentsChanged(const QVariant&)));
    
    connect(mBody, SIGNAL(contentsChanged(const QVariant&)),
            mMsgMonitor, SLOT(handleContentsChanged(const QVariant&))); 
    
    connect(mBody,SIGNAL(enableMenuAction(int,bool)),this,SIGNAL(enableMenuAction(int,bool)));
    
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::addCcBcc
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::addCcBcc(bool needFocus)
{
    if(mCcField && mBccField)
    { // do nothing if already present
        return;
    }

    mCcField    = new MsgUnifiedEditorAddress( LOC_CC, this );
    mCcField->setObjectName("cc");

    mBccField   = new MsgUnifiedEditorAddress( LOC_BCC, this );
    mBccField->setObjectName("bcc");

    mCcField->skipMaxRecipientQuery(true);
    mBccField->skipMaxRecipientQuery(true);

    connect(mCcField, SIGNAL(contentsChanged(const QVariant&)),
        mMsgMonitor, SLOT(handleContentsChanged(const QVariant&)));

    connect(mBccField, SIGNAL(contentsChanged(const QVariant&)),
        mMsgMonitor, SLOT(handleContentsChanged(const QVariant&)));

    HbWidget* groupWidget = new HbWidget(this);
    groupWidget->setContentsMargins(0,0,0,0);

    QGraphicsLinearLayout* ccBccLayout = new QGraphicsLinearLayout(Qt::Vertical, groupWidget);
    ccBccLayout->setContentsMargins(0,0,0,0);

    qreal vItemSpacing = 0.0;    
    style()->parameter("hb-param-margin-gene-middle-vertical",vItemSpacing);
    ccBccLayout->setSpacing(vItemSpacing);
    ccBccLayout->addItem(mCcField);
    ccBccLayout->addItem(mBccField);

    HbGroupBox* groupBox = new HbGroupBox(0);  
    groupBox->setObjectName("groupBox");

    groupBox->setContentWidget(groupWidget);
    groupBox->setHeading(LOC_OTHER_RECIPIENTS_EXPAND);
    mMainLayout->insertItem(1,groupBox);
    connect(groupBox, SIGNAL(toggled(bool)), this, SLOT(updateOtherRecipientCount(bool)));

    //emit signal to remove CcBcc action
    emit enableMenuAction(CCBCC, false);

    this->updateGeometry();
    
    if(needFocus)
    {
        setFocus(mCcField);
    }
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::addSubject
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::addSubject(bool needFocus)
{
    // do nothing if already present
    if(mSubjectField)
    { 
        return;
    }

    mSubjectField = new MsgUnifiedEditorSubject(this);

    int index = 0;
    if(mCcField && mBccField)
    {
        index = 2;
    }
    else
    {
        index = 1;
    }

    mMainLayout->insertItem(index,mSubjectField);
    connect(mSubjectField, SIGNAL(contentsChanged(const QVariant&)),
            mMsgMonitor, SLOT(handleContentsChanged(const QVariant&)));

    //emit signal to remove CcBcc action
    emit enableMenuAction(SUBJECT, false); 
    
    if(needFocus)
    {
        setFocus(mSubjectField);
    }
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::setImage
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::setImage(const QString& path, bool draftMessage)
{
    mBody->setImage(path,draftMessage);
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::setAudio
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::setAudio(const QString& filePath)
{
    mBody->setAudio(filePath);
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::setFocus
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::setFocus(MsgUnifiedEditorBaseWidget* item)
{
    if(item)
    {
        item->setFocus();  
    }
    
    //open vkb
    postInputPanelEvent();
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::changePriority
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::changePriority()
{
    HbAction* action = qobject_cast<HbAction*>(sender());

    ConvergedMessage::Priority priority = ConvergedMessage::Normal;
   if(action)
        {
        int data = action->data().toInt();
        priority = ConvergedMessage::Priority(data);
        }

    addSubject();
    mSubjectField->setPriority(priority);
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::updateOtherRecipientCount
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::updateOtherRecipientCount(bool state)
{
    HbGroupBox* groupBox = qobject_cast<HbGroupBox*>(sender());
    if(groupBox)
    {
        if(!state)
        {
           groupBox->setHeading(LOC_OTHER_RECIPIENTS_EXPAND);
        }
        else
        {
            int addrCount = mCcField->addressCount();
            addrCount += mBccField->addressCount();
            if(addrCount > 0)
            {
                groupBox->setHeading(LOC_OTHER_RECIPIENTS(addrCount));    
            }
        }
    }
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::contactsValid
//
//---------------------------------------------------------------
bool MsgUnifiedEditorScrollArea::contactsValid()
{
        bool res = ( !mToField->validateContacts() ||
                    (mCcField && !mCcField->validateContacts()) ||
                    (mBccField && !mBccField->validateContacts()) );
        
        return !res;
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::currentAddress
//
//---------------------------------------------------------------
ConvergedMessageAddress* MsgUnifiedEditorScrollArea::currentAddress()
{
    ConvergedMessageAddress* currentAdd = NULL;
    
    ConvergedMessageAddressList addList = mToField->addresses();
    int count = addList.count();
    if(count)
    {
        currentAdd = addList.takeFirst();
    }
    
    while(addList.count())
    {
        ConvergedMessageAddress* obj =  addList.takeFirst();
        delete obj;
    }
    
    return currentAdd;
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::packMessage
//
//---------------------------------------------------------------
int MsgUnifiedEditorScrollArea::packMessage(ConvergedMessage &msg, bool isSave)
{
    // If isSave is true (save to draft usecase), then don't remove duplicates
    // If isSave is false (send usecase), then remove duplicates
    bool removeDuplicates = !isSave;
    ConvergedMessageAddressList addresses = mToField->addresses(removeDuplicates);
    
    ConvergedMessageAddressList ccAddresses;
    ConvergedMessageAddressList bccAddresses;
    ConvergedMessageAttachmentList mediaList;
    int errorCode = 0;
    //Don't format the addresses for save to drfats case
    if(!isSave)
    {
       formatAddresses(addresses);
    }
    
    msg.addToRecipients(addresses);

    if(MsgUnifiedEditorMonitor::messageType() == ConvergedMessage::Mms)
    {
        if(mCcField)
        {
            ccAddresses = mCcField->addresses(removeDuplicates);
        }

        if(mBccField)
        {
            bccAddresses = mBccField->addresses(removeDuplicates);
        }

        if(removeDuplicates)
        {
            int matchDigitsCount = MsgUnifiedEditorAddress::contactMatchDigits();
            //comapre cc and to field,remove duplicate from cc
            foreach(ConvergedMessageAddress *ccAddress,ccAddresses)
            {
                foreach(ConvergedMessageAddress *toAddress,addresses)
                {
                    if(0 == ccAddress->address().right(matchDigitsCount).compare(toAddress->address().right(matchDigitsCount)))
                    {
                        ccAddresses.removeOne(ccAddress);
                    }
                }
            }
            //comapre bcc and cc field,remove duplicate from bcc
            foreach(ConvergedMessageAddress *bccAddress,bccAddresses)
            {
                foreach(ConvergedMessageAddress *ccAddress,ccAddresses)
                {
                    if(0 == bccAddress->address().right(matchDigitsCount).compare(ccAddress->address().right(matchDigitsCount)))
                    {
                        bccAddresses.removeOne(bccAddress);
                    }
                }
            }
            //comapre bcc and to field,remove duplicate from bcc
            foreach(ConvergedMessageAddress *bccAddress,bccAddresses)
            {
                foreach(ConvergedMessageAddress *toAddress,addresses)
                {
                    if(0 == bccAddress->address().right(matchDigitsCount).compare(toAddress->address().right(matchDigitsCount)))
                    {
                        bccAddresses.removeOne(bccAddress);
                    }
                }
            }
        }

        if(ccAddresses.count()>0)
        {
        //Don't format the addresses for save to drfats case
        if(!isSave)
        {
           formatAddresses(ccAddresses);
        }        
        msg.addCcRecipients(ccAddresses);
        }
        if(bccAddresses.count()>0)
        {
        //Don't format the addresses for save to drfats case
        if(!isSave)
        {
           formatAddresses(bccAddresses);        
        }
        msg.addBccRecipients(bccAddresses);
        }
        if(mSubjectField)
        {
            msg.setSubject(mSubjectField->text());
            msg.setPriority(mSubjectField->priority());
        }

        QStringList mediafiles(mBody->mediaContent());
        if (!mediafiles.isEmpty())
        {
            for (int i = 0; i < mediafiles.size(); ++i)
            {
                if(QFile::exists(mediafiles.at(i)))
                {
                ConvergedMessageAttachment* attachment =
                    new ConvergedMessageAttachment(
                        mediafiles.at(i),
                        ConvergedMessageAttachment::EInline);
                mediaList << attachment;
                }
                else
                {   mBody->removeMediaContent(mediafiles.at(i));
                    errorCode = KErrNotFound;
                }
            }

        }
        if(mediaList.count() > 0)
        {
            msg.addAttachments(mediaList);
        }
    }

    // sms/mms attachment list
    ConvergedMessageAttachmentList attachmentList;
        if(mAttachmentContainer)
        {
            MsgUnifiedEditorAttachmentList editorAttachmentList =
                mAttachmentContainer->attachmentList();
                for (int i = 0; i < editorAttachmentList.count(); ++i)
                {
                    if(QFile::exists(editorAttachmentList.at(i)->path()))
                    {
                        ConvergedMessageAttachment* attachment =
                                                new ConvergedMessageAttachment(
                                                    editorAttachmentList.at(i)->path(),
                                                    ConvergedMessageAttachment::EAttachment);
                                            attachmentList << attachment;    
                    }
                    else
                    {
                        mAttachmentContainer->deleteAttachment(editorAttachmentList.at(i));
                        errorCode = KErrNotFound;
                    }   
                }
            }
        if(attachmentList.count() > 0)
        {
            msg.addAttachments(attachmentList);
        }
        return errorCode;
}

// ----------------------------------------------------------------------------
// MsgUnifiedEditorScrollArea::formatAddresses
// @see header
// ----------------------------------------------------------------------------
void MsgUnifiedEditorScrollArea::formatAddresses(ConvergedMessageAddressList& addresses)
{       
    for(int i=0; i < addresses.count() ;i++ )
    {
        QString addr = addresses[i]->address();
        
        HBufC *tempAddr = XQConversions::qStringToS60Desc(addr);     
            
        TPtr ptr = tempAddr->Des();
                    
         // Note: This is just to parse spaces etc away from phonenumbers.
         //       Ignore EFalse returned for email addresses.   
        CommonPhoneParser::ParsePhoneNumber(ptr , 
                                            CommonPhoneParser::ESMSNumber );        
       
        addr = XQConversions::s60DescToQString(tempAddr->Des()); 
        
        addresses[i]->setAddress(addr);
        
        delete tempAddr;                                                       
    }       
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::addAttachment
//
//---------------------------------------------------------------
int MsgUnifiedEditorScrollArea::addAttachment(const QString& filepath)
{
    // do nothing if filepath is empty
    if(filepath.isEmpty())
    {
        return MsgAttachmentContainer::EAddSuccess;
    }

    if(!mAttachmentContainer)
    {
        mAttachmentContainer = new MsgAttachmentContainer(this);
        connect(mAttachmentContainer, SIGNAL(emptyAttachmentContainer()),
                this, SLOT(removeAttachmentContainer()));
        connect(mAttachmentContainer, SIGNAL(contentsChanged(const QVariant&)),
                mMsgMonitor, SLOT(handleContentsChanged(const QVariant&)));
        
        int index = mMainLayout->count() - 1;
        mMainLayout->insertItem(index,mAttachmentContainer);
    }

    int ret = mAttachmentContainer->addAttachment(filepath);
    if(ret != MsgAttachmentContainer::EAddSuccess)
    {
        // delete container, if it is empty
        if(mAttachmentContainer->count() == 0)
        {
            removeAttachmentContainer();
        }
    }
    return ret;
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::removeAttachmentContainer
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::removeAttachmentContainer()
{
    if(mAttachmentContainer)
    {
        mMainLayout->removeItem(mAttachmentContainer);
        mAttachmentContainer->setParent(NULL);
        delete mAttachmentContainer;
        mAttachmentContainer = NULL;
    }
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::addAttachments
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::addAttachments(const QStringList files)
{    
    int fcount = files.count();
    int i=0;
    for(i=0; i<fcount; i++)
    {
        int status = addAttachment(files.at(i));
        if(status == MsgAttachmentContainer::EAddSizeExceed)
        {
            QString displayStr = QString(LOC_UNABLE_TO_ADD_ATTACHMENTS)
                    .arg(fcount-i).arg(fcount);
            HbNotificationDialog::launchDialog(displayStr);
            break;
        }
    }
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::fileNameInUse
//
//---------------------------------------------------------------
bool MsgUnifiedEditorScrollArea::fileNameInUse(const QString& fileName)
{
    bool inUse = false;
    
    if(mAttachmentContainer)
    {
        inUse = mAttachmentContainer->fileNameInUse(fileName);
    }
    
    return inUse;
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::scrollByAmount
//
//---------------------------------------------------------------
bool MsgUnifiedEditorScrollArea::scrollByAmount(const QPointF &delta)
{
    if(mEnableScrolling)
    {
        return HbScrollArea::scrollByAmount(delta);
    }
    else
    {
        return false;
    }
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::enableScrolling
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::enableScrolling(bool enable)
{
    mEnableScrolling = enable;
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::postInputPanelEvent
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::postInputPanelEvent()
{
    // This opens the VKB
    QInputContext *ic = qApp->inputContext();
    if (ic)
    {
        QEvent event(QEvent::RequestSoftwareInputPanel);
        ic->filterEvent(&event);
    }
}

//---------------------------------------------------------------
// MsgUnifiedEditorScrollArea::populateContent
//
//---------------------------------------------------------------
void MsgUnifiedEditorScrollArea::populateContent(const ConvergedMessage& msg, bool draftMessage, bool checkForInline)
{
    mToField->skipMaxRecipientQuery(true);

    mToField->setAddresses(msg.toAddressList(),draftMessage);
    
    if(msg.ccAddressList().count() > 0 )
    {
        if(!mCcField)
        {
            addCcBcc();
        }
        mCcField->setAddresses(msg.ccAddressList(),draftMessage);
    }
    
    if(msg.bccAddressList().count() > 0 )
    {
        if(!mBccField)
        {
            addCcBcc();
        }
        mBccField->setAddresses(msg.bccAddressList(),draftMessage);
    }
    
    if(msg.subject().size() > 0)
    {
        if(!mSubjectField)
        {
            addSubject();
        }
        mSubjectField->setText(msg.subject());
    }

    if(msg.priority()==ConvergedMessage::High ||
        msg.priority() == ConvergedMessage::Low)
    {
        if(!mSubjectField)
        {
            addSubject();
        }
        mSubjectField->setPriority(msg.priority());
    }


    ConvergedMessageAttachmentList attachmentList = msg.attachments();

    UniEditorGenUtils* genUtils = q_check_ptr(new UniEditorGenUtils);

    QStringList pendingAttList;

    int attachmentCount = attachmentList.count();

    for( int i=0; i < attachmentCount; i++ )
    {
        QString filePath = msg.attachments().at(i)->filePath();
        
        bool inlineContent = true;
        
        if(checkForInline)
        {
            inlineContent = (attachmentList.at(i)->attachmentType() == ConvergedMessageAttachment::EInline);
        }

        if (inlineContent)
        {
            int imageSize=0;
            QString mimeType;            
            TMsgMediaType mediaType = EMsgMediaUnknown;
            
            TRAP_IGNORE(genUtils->getFileInfoL(filePath,imageSize,
                        mimeType,mediaType));

            switch(mediaType)
            {
                case EMsgMediaImage:
                {
                    mBody->setImage(filePath,draftMessage);
                    break;
                }
                case EMsgMediaAudio:
                {
                    mBody->setAudio(filePath);
                    break;
                }
                default:
                {
                    pendingAttList << filePath;
                    break;
                }
            }
        }
        else
        {
            pendingAttList << filePath;
        }
    }
    // add pending attachments to editor
    addAttachments(pendingAttList);

    delete genUtils;
    
    // ensure that any msg-type change after this are shown
    mToField->skipMaxRecipientQuery(false);

}
