/*
 * 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: Listen to conversation server events and parse the 
 * events. These parse infomation passed to notifications and indications.
 *
 */

// SYSTEM INCLUDES
#include <msvapi.h>
#include <ccsclientconversation.h>
#include <ccsrequesthandler.h>
#include <ccsconversationentry.h>
#include <xqservicerequest.h>
#include <QString>
#include <w32std.h>
#include <apgtask.h> 
#include <XQSettingsManager>
#include <xqaiwrequest.h>
#include <xqappmgr.h>
#include <xqpublishandsubscribeutils.h>
#include <xqsystemtoneservice.h>
#include <xqconversions.h>
#include <QThreadPool>
#include <ProfileEngineInternalCRKeys.h>
#include <hwrmvibra.h>

//USER INCLUDES
#include "msgnotifier.h"
#include "msgnotifier_p.h"
#include "msgstorehandler.h"
#include "msginfodefs.h"
#include "conversationidpsconsts.h"
#include "debugtraces.h"

const XQCentralRepositorySettingsKey silenceModeKey(KCRUidProfileEngine.iUid, KProEngSilenceMode);

// ----------------------------------------------------------------------------
// MsgNotifierPrivate::MsgNotifierPrivate
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------
MsgNotifierPrivate::MsgNotifierPrivate(MsgNotifier* MsgNotifier) :
    q_ptr(MsgNotifier), mCvServer(NULL), iMsgStoreHandler(NULL),
    mSettingsManager(NULL),mPSUtils(NULL)
{
    QDEBUG_WRITE("MsgNotifierPrivate::MsgNotifierPrivate : Enter")

    initL();
    QDEBUG_WRITE("MsgNotifierPrivate::MsgNotifierPrivate : Exit")
}

// ----------------------------------------------------------------------------
// MsgNotifierPrivate::~MsgNotifierPrivate
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------
MsgNotifierPrivate::~MsgNotifierPrivate()
{
    QDEBUG_WRITE("MsgNotifierPrivate::~MsgNotifierPrivate : Enter")
    if (mCvServer) {
        TRAP_IGNORE(mCvServer->RemoveConversationListChangeEventL(this));
        delete mCvServer;
        mCvServer = NULL;
    }

    if (iMsgStoreHandler) {
        delete iMsgStoreHandler;
        iMsgStoreHandler = NULL;
    }
    
    if(mPSUtils)
        {
        delete mPSUtils;
        }
    
    if(mSettingsManager)
        {
        delete mSettingsManager;
        }
    
    if(mSts)
        {
        delete mSts;
        mSts = NULL;
        }
    
    if(mVibra)
        {
        delete mVibra;
        mVibra = NULL;
        }
    QDEBUG_WRITE("MsgNotifierPrivate::~MsgNotifierPrivate : Exit")
}

// ----------------------------------------------------------------------------
// MsgNotifierPrivate::initL
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------
void MsgNotifierPrivate::initL()
{
    QDEBUG_WRITE("MsgNotifierPrivate::initL : Enter")

    mCvServer = CCSRequestHandler::NewL();
    mCvServer->RequestConversationListChangeEventL(this);
    iMsgStoreHandler = new MsgStoreHandler(this, mCvServer);
    updateUnreadIndications(true); 
    updateOutboxIndications();

    QT_TRYCATCH_LEAVING(mSettingsManager = new XQSettingsManager());
    
    // define property
    QT_TRYCATCH_LEAVING(mPSUtils = new XQPublishAndSubscribeUtils(*mSettingsManager));
    
    XQPublishAndSubscribeSettingsKey convIdKey(
            KMsgCVIdProperty, KMsgCVIdKey);
    bool success = mPSUtils->defineProperty(convIdKey, 
                            XQSettingsManager::TypeInt);
    
    QDEBUG_WRITE_FORMAT("MsgNotifierPrivate::initL "
                        "property creation ret value",success)
    
    // write -1 initially 
    success = mSettingsManager->writeItemValue(convIdKey,-1);
    
    QDEBUG_WRITE_FORMAT("MsgNotifierPrivate::initL "
                           "writing ret value",success)
    
    QT_TRYCATCH_LEAVING(mSts = new XQSystemToneService());
    
    mVibra = CHWRMVibra::NewL();
    
    QDEBUG_WRITE("MsgNotifierPrivate::initL : Exit")
}

// ----------------------------------------------------------------------------
// MsgNotifierPrivate::AddConversationList
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------
void MsgNotifierPrivate::AddConversationList(
                  const CCsClientConversation& aClientConversation)
{
    QCRITICAL_WRITE("MsgNotifierPrivate::AddConversationList : Enter")

    processListEntry(aClientConversation);
    updateUnreadIndications();

    QCRITICAL_WRITE("MsgNotifierPrivate::AddConversationList : Exit")
}

// ----------------------------------------------------------------------------
// MsgNotifierPrivate::DeleteConversationList
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------
void MsgNotifierPrivate::DeleteConversationList( 
	                const CCsClientConversation& /*aClientConversation*/)
{
    QDEBUG_WRITE("MsgNotifierPrivate::DeleteConversationList : Enter")
    updateUnreadIndications();
    QDEBUG_WRITE("MsgNotifierPrivate::DeleteConversationList : Exit")
}

// ----------------------------------------------------------------------------
// MsgNotifierPrivate::ModifyConversationList
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------
void MsgNotifierPrivate::ModifyConversationList(const CCsClientConversation& aClientConversation)
{
    QCRITICAL_WRITE("MsgNotifierPrivate::ModifyConversationList : Enter")

    processListEntry(aClientConversation);
    updateUnreadIndications();

    QCRITICAL_WRITE("MsgNotifierPrivate::ModifyConversationList : Exit")
}

// ----------------------------------------------------------------------------
// MsgNotifierPrivate::RefreshConversationList
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------
void MsgNotifierPrivate::RefreshConversationList()
{

}

// ----------------------------------------------------------------------------
// MsgNotifierPrivate::processListEntry
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------
void MsgNotifierPrivate::processListEntry(
        const CCsClientConversation& aClientConversation)
    {
    QCRITICAL_WRITE("MsgNotifierPrivate::processListEntry : Enter")
    
    CCsConversationEntry* convEntry = 
                                 aClientConversation.GetConversationEntry();
    
    QDEBUG_WRITE_FORMAT("MsgNotifierPrivate::processListEntry Direction",
                                                convEntry->ConversationDir())
    QDEBUG_WRITE_FORMAT("MsgNotifierPrivate::processListEntry New Entry Attribute",
                                                convEntry->IsAttributeSet(ECsAttributeNewEntryAdded))
    QDEBUG_WRITE_FORMAT("MsgNotifierPrivate::processListEntry Unread Attribute",
                                                convEntry->IsAttributeSet(ECsAttributeUnread))
   
    if((convEntry->ConversationDir() == ECsDirectionIncoming)
            && convEntry->IsAttributeSet(ECsAttributeNewEntryAdded) 
            && convEntry->IsAttributeSet(ECsAttributeUnread))
        {
        QDEBUG_WRITE("processListEntry : Processing data for Notification")
        
        NotificationData notifData;
        notifData.msvEntryId = convEntry->EntryId(); 
        notifData.mConversationId = aClientConversation.GetConversationEntryId();
        notifData.mMsgType = static_cast<int>(convEntry->GetType());
        
        HBufC* displayName = aClientConversation.GetDisplayName();
        HBufC* number =  convEntry->Contact();
        HBufC* descrp =  convEntry->Description();
        
        if(displayName)
            {
            notifData.mDisplayName = 
                                XQConversions::s60DescToQString(*displayName);
            }        
        if(number)
            {
            notifData.mContactNum =  XQConversions::s60DescToQString(*number);
            }
        if(descrp)
            {
            notifData.mDescription = XQConversions::s60DescToQString(*descrp);
            }
        
        QVariant silenceMode = mSettingsManager->readItemValue(silenceModeKey, XQSettingsManager::TypeInt);
        int silent = silenceMode.toInt();
        if(silent < 1)
            {
            //Play new message alert tone.
            mSts->playTone(XQSystemToneService::SmsAlertTone);
            }
        // Execute the vibra effect.
        if (mVibra) 
            {
            TInt err = KErrNone;
            TRAP(err,mVibra->StartVibraL(1000));
            }
        
        // check whether opened cv id and received 
        // cv id are same and show notification
        if( showNotification(notifData.mConversationId ))
            {
             q_ptr->displayNewMessageNotification(notifData);
             QDEBUG_WRITE("processListEntry : Notification display called")
            }
       
        }
    
    QCRITICAL_WRITE("MsgNotifierPrivate::processListEntry : Exit")
    }

// ----------------------------------------------------------------------------
// MsgNotifierPrivate::updateUnreadIndications
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------
void MsgNotifierPrivate::updateUnreadIndications(bool bootup)
{
    QDEBUG_WRITE("MsgNotifierPrivate::updateIndicationsL : Enter")

    int unreadCount(0);
   if(bootup)
   {
       TRAP_IGNORE(unreadCount = iMsgStoreHandler->GetUnreadMessageCountL());
   }
   else
   {
       TRAP_IGNORE(unreadCount = mCvServer->GetTotalUnreadCountL());
   }

    QDEBUG_WRITE_FORMAT("MsgNotifierPrivate::"
        "updateIndications unreadCount = ",unreadCount );

    //activate or deactivate indications based on unread count
    q_ptr->updateUnreadIndications(unreadCount);

    QDEBUG_WRITE("MsgNotifierPrivate::updateIndicationsL : Exit")
}

// ----------------------------------------------------------------------------
// MsgNotifierPrivate::updateOutboxIndications
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------
void MsgNotifierPrivate::updateOutboxIndications()
{

    MsgInfo failedIndicatorData;
    MsgInfo pendingIndicatorData;
    TInt err = KErrNone;
    
    TRAP(err, iMsgStoreHandler->GetOutboxEntriesL(failedIndicatorData,pendingIndicatorData));

    q_ptr->updateOutboxIndications(failedIndicatorData);
    q_ptr->updateOutboxIndications(pendingIndicatorData);
}


// ----------------------------------------------------------------------------
// MsgNotifierPrivate::displayOutboxIndications
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------

void MsgNotifierPrivate::displayOutboxIndications(MsgInfo data)
	{
		q_ptr->updateOutboxIndications(data);
	}

// ----------------------------------------------------------------------------
// MsgNotifierPrivate::displayFailedNote
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------
void MsgNotifierPrivate::displayFailedNote(MsgInfo info)
    {
    QDEBUG_WRITE("MsgNotifierPrivate::displayFailedNote start.")
            
    // check whether opened cv id and received 
    // cv id are same then dont show failed note
    if (!showNotification(info.mConversationId))
        {
        return;
        }

    //Even if name string is empty we shall add name into args
    QString nameString;

    info.mDisplayName.removeDuplicates();
    info.mDisplayName.sort();

    nameString.append(info.mDisplayName.at(0));
    for (int i = 1; i < info.mDisplayName.count(); ++i)
        {
        nameString.append(", ");
        nameString.append(info.mDisplayName.at(i));
        }

    // create request arguments
    QVariantList args;
    args << QVariant(nameString);
    args << info.mConversationId;
    args << info.mMessageType;

    // TODO: use XQAiwRequest
    XQServiceRequest snd("messaging.com.nokia.symbian.MsgErrorNotifier",
            "displayErrorNote(QVariantList)", false);

    snd << args;
    snd.send();
    
    QDEBUG_WRITE("MsgNotifierPrivate::displayFailedNote end.")
    }

// ----------------------------------------------------------------------------
// MsgNotifierPrivate::showNotification
// @see MsgNotifierPrivate.h
// ----------------------------------------------------------------------------
bool MsgNotifierPrivate::showNotification(int receivedMsgConvId)
{
    bool showNotification = true;
    
    RWsSession wsSession ;
    wsSession.Connect();

    TApaTaskList taskList( wsSession );
    TApaTask task = taskList.FindApp(KMsgAppUid); // find msgapp is running

    if(task.Exists())
        {
        TApaTask foregndtask =   taskList.FindByPos(0) ;  // foreground app
        // compare  window group id  
        // if application is in foregorund, then check the currently
        // opened conversation is same as received one.
        if(task.WgId() == foregndtask.WgId() )
            {
            // get the current conversation ID
            XQPublishAndSubscribeSettingsKey convIdKey( KMsgCVIdProperty, 
                    KMsgCVIdKey);
            QVariant value = mSettingsManager->readItemValue(convIdKey, 
                    XQSettingsManager::TypeInt);

            int openedConvId  = value.toInt();
            if( openedConvId == receivedMsgConvId)
                {
                showNotification = false;
                QDEBUG_WRITE("processListEntry : Notification not shown")
                }
            }
        }

    wsSession.Close();
    return showNotification;
}
// ----------------------------------------------------------------------------
// MsgNotifierPrivate::PartialDeleteConversationList
// @see mcsconversationclientchangeobserver.h
// ----------------------------------------------------------------------------
void MsgNotifierPrivate::PartialDeleteConversationList(
        const CCsClientConversation& /*aClientConversation*/){/*empty implementation*/}


// ----------------------------------------------------------------------------
// MsgNotifierPrivate::ShowClass0Message
// @see msgnotifier_p.h
// ----------------------------------------------------------------------------

void MsgNotifierPrivate::ShowClass0Message(Class0Info& class0Info)
{
    QCRITICAL_WRITE("flashmsgnotifier BEGIN");
    QThreadPool::globalInstance()->start(new Class0SmsServiceTask(class0Info));
    QCRITICAL_WRITE("flashmsgnotifier END");
}




// ----------------------------------------------------------------------------
// Class0SmsServiceTask::Class0SmsServiceTask
// @see msgnotifier_p.h
// ----------------------------------------------------------------------------  
Class0SmsServiceTask::Class0SmsServiceTask(Class0Info& class0Info):
mClass0info(class0Info)
     {     
     }

// ----------------------------------------------------------------------------
// Class0SmsServiceTask::~Class0SmsServiceTask
// @see msgnotifier_p.h
// ----------------------------------------------------------------------------   
Class0SmsServiceTask::~Class0SmsServiceTask()
     {     
     }
     
// ----------------------------------------------------------------------------
// Class0SmsServiceTask::run
// @see msgnotifier_p.h
// ----------------------------------------------------------------------------   
void Class0SmsServiceTask::run()
     {
   	  QList<QVariant> args;
      QString serviceName("flashmsgnotifier");
      QString interfaceName("com.nokia.symbian.IFlashMsgNotifier");
      QString operation("displayFlashMsg(QByteArray)");
      XQAiwRequest* request;
      XQApplicationManager appManager;

      request = appManager.create(interfaceName, operation, false); //non-embedded

      if ( request == NULL )
      {
          QCRITICAL_WRITE("flashmsgnotifier request == NULL");
          return; 
      }

      QByteArray ba; 
      QDataStream stream(&ba, QIODevice::ReadWrite);
      stream << mClass0info.body;
      stream << mClass0info.address;
      stream << mClass0info.alias;
      stream << mClass0info.time;     
      stream << mClass0info.messageId;
       
      args << ba;
      request->setArguments(args);    
       
      if(!request->send())
      {
         QString lastErr;
          lastErr = request->lastErrorMessage();
          QDEBUG_WRITE_FORMAT("flashmsgnotifier launch failed", lastErr);
      }
       
      QCRITICAL_WRITE("flashmsgnotifier END");
      delete request;  
     }

//EOF
