/*
* Copyright (c) 2002-2008 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:  Plugin implementation of global list query.
*
*/

#include "AknSystemListPopup.h"
#include <AknNotifyStd.h>

#include <avkon.rsg>
#include <eikbtgpc.h>
#include <eikenv.h>
#include <avkon.hrh>
#include <bautils.h>
#include "AknListQueryNotificationDialog.h"
#include <aknnotpi.rsg>
#include <AknGlobalListQuery.h>
#include <s32mem.h>
#include <uikon/eiksrvui.h>
#include <AknNotifySignature.h>

#include <AknMediatorFacade.h>
#include <aknSDData.h>
#include <secondarydisplay/AknSecondaryDisplayDefs.h>
 
#include "AknAppsKeyCleanup.inl"

const TInt KListQueryItemLength = 64;
const TInt KCharsInTInt = 4; // TInt32 takes 4 chars.
const TInt KArrayGranularity = 3;

CAknGlobalListQuerySubject* CAknGlobalListQuerySubject::NewL()
    {
    CAknGlobalListQuerySubject* self = new (ELeave) CAknGlobalListQuerySubject(); 
    CleanupStack::PushL(self);
    self->ConstructL(); 
    CleanupStack::Pop(self);
    return self;
    }

CAknGlobalListQuerySubject::CAknGlobalListQuerySubject()
: iPending(EFalse)
    {
    iStoredEikonEnv = CEikonEnv::Static();
    }

void CAknGlobalListQuerySubject::ConstructL()
    {
    }

CAknGlobalListQuerySubject::~CAknGlobalListQuerySubject()
    {
    //delete iDlg;
    Cancel();
    
    // Complete the RMessage if we need to.
    if (iPending)
        {
        iMessage.Complete(KErrDied);
        }

    delete iArray;
    delete iHeading;
    }

void CAknGlobalListQuerySubject::Release()
    {
    delete this;
    }

CAknGlobalListQuerySubject::TNotifierInfo CAknGlobalListQuerySubject::RegisterL()
    {
    iInfo.iUid = KAknGlobalListQueryUid;
    iInfo.iChannel = EAknNotifierChannelList;
    iInfo.iPriority = ENotifierPriorityHigh;
    return iInfo;
    }
    
CAknGlobalListQuerySubject::TNotifierInfo CAknGlobalListQuerySubject::Info() const
    {
    return iInfo;
    }

TPtrC8 CAknGlobalListQuerySubject::StartL(const TDesC8& /*aBuffer*/)
    {
    return KNullDesC8();
    }

void CAknGlobalListQuerySubject::StartL(const TDesC8& aBuffer, TInt /*aReplySlot*/, 
    const RMessagePtr2& aMessage)
    {
    if (iPending)
        {
        aMessage.Complete(KErrInUse);
        return;
        }

    RDesReadStream readStream(aBuffer);
    if (aBuffer.Length() < KCharsInTInt || readStream.ReadInt32L() != KAKNNOTIFIERSIGNATURE)
        {
        User::Leave(KErrArgument);
        }

    iMessage = aMessage;
    iSelectFirst = readStream.ReadInt16L();
    TInt count = readStream.ReadInt16L();

    // Create array
    delete iArray;
    iArray = 0;
    iArray = new (ELeave) CDesCArrayFlat(KArrayGranularity);
    
    TBuf<KListQueryItemLength> arrayItem;

    for (TInt ii = 0; ii < count; ii++)
        {
        readStream >> arrayItem;
        iArray->AppendL(arrayItem);
        }
        
    TInt headingLength = readStream.ReadInt16L();
    delete iHeading;
    iHeading = 0;
    
    if (headingLength != KErrNotFound)
        {
        iHeading = HBufC::NewL(headingLength);
        TPtr ptr = iHeading->Des();
        readStream >> ptr;
        }

    CAknSDData* sddata = 0;
    if (readStream.ReadInt8L())
        {
        sddata = new (ELeave) CAknSDData();
        CleanupStack::PushL(sddata);
        readStream >> *sddata;
        }

    delete iDlg;
    iDlg = NULL;
        
    iDlg = new (ELeave) CAknListQueryNotificationDialog(&iListIndex, this, &iDlg);
    if (sddata)
        {
        CArrayFixFlat<TInt>* array = 0;
        CleanupStack::PushL(array); // even as null
        if (sddata->iAdditionalData && 
            sddata->iAdditionalData->Length() > 2*sizeof(TInt32)) // command id and count
            {
            RDesReadStream strm(*sddata->iAdditionalData);
            CleanupClosePushL(strm);
            TInt count = strm.ReadInt32L(); // recycling...
            if (count == EAknListQueryItemsInfo)
                {
                count = strm.ReadInt32L();
                array = new (ELeave) CArrayFixFlat<TInt>(1);
                for (TInt i = 0; i < count; i++)
                    {
                    array->AppendL(strm.ReadInt32L());
                    }
                }   
            CleanupStack::PopAndDestroy();
        
            // Tidy additional data so that there will not be two item arrays.
            TInt bytesToRemove = (count + 2) * 4;
            HBufC8* newDes = 0;
            if (bytesToRemove != sddata->iAdditionalData->Length())
                {
                newDes = sddata->iAdditionalData->Mid(bytesToRemove).AllocL();                
                }           
            delete sddata->iAdditionalData;
            sddata->iAdditionalData = newDes;
            }
            
        iDlg->PublishDialogL(sddata->iDialogIdx, sddata->iCategory, array);
        CleanupStack::Pop(); // Ownership transferred to dialog successfully. 
        if (sddata->iAdditionalData)
            {
            CAknMediatorFacade* cover_info = AknMediatorFacade(iDlg);
            if (cover_info)
                {
                cover_info->BufStream() << *(sddata->iAdditionalData);
                cover_info->BufStream().CommitL();
                }
            }
        CleanupStack::PopAndDestroy(sddata);
        }
    else
        { 
        // If secondary display data hasn't been defined, then the unidentified
        // list query identifier is published to the secondary display.
        iDlg->PublishDialogL(EAknUnidentifiedListQuery, KAknSecondaryDisplayCategory);
        }        

    if (!iAppsKeySuppressed)
        {
        ((CAknNotifierAppServerAppUi*)(iStoredEikonEnv->EikAppUi()))->SuppressAppSwitching(ETrue);
        }
    CleanupStack::PushL(TCleanupItem(ReleaseAppsKey, 0));    
    
    if (!iHeading) 
        {
        iDlg->PrepareLC(R_GLOBAL_LIST_QUERY);
        }
    else
        {
        iDlg->PrepareLC(R_GLOBAL_LIST_QUERY_WITH_HEADING);
        iDlg->QueryHeading()->SetTextL(iHeading->Des());
        }
        
    iDlg->SetOwnershipType(ELbmOwnsItemArray);
    iDlg->SetItemTextArray(iArray);
    TInt itemCount = iArray->Count();
    iArray = 0;

    // If the list is not empty, the selection index must point to an existing item. 
    // Otherwise a panic will occur.
    if (itemCount && (iSelectFirst < 0 || iSelectFirst > itemCount - 1))
        {
        User::Leave(KErrArgument);
        }    
    
    CEikListBox* listBox = iDlg->ListBox();
    if (itemCount)
        {
        listBox->SetCurrentItemIndex(iSelectFirst);
        }
    listBox->UpdateScrollBarsL();
   
    iDlg->RunLD();
    
    CleanupStack::Pop(); // Apps key cleanup.
    iAppsKeySuppressed = ETrue;
    iPending = ETrue;
    }

void CAknGlobalListQuerySubject::Cancel()
    {
    delete iDlg;
    iDlg = NULL;
    TRAP_IGNORE(QueryDismissedL(EAknSoftkeyCancel));
    }

TPtrC8 CAknGlobalListQuerySubject::UpdateL(const TDesC8& aBuffer)
    {
    if (!iDlg)
        {
        return KNullDesC8();
        }

    // Get parameters.
    SAknNotifierPackage<SAknGlobalListQueryParams>* params 
        = (SAknNotifierPackage<SAknGlobalListQueryParams>*)aBuffer.Ptr();

    if (aBuffer.Length() < 0 
        || (TUint)aBuffer.Length() < sizeof(SAknNotifierPackage<SAknGlobalListQueryParams>)
        || params->iSignature != KAKNNOTIFIERSIGNATURE)
        {
        User::Leave(KErrArgument);
        }

    TInt cmd = params->iParamData.iCmd;
    TKeyEvent keyEvent;
    keyEvent.iRepeats = 0;
    TEventCode eventType = EEventKey;
    switch (cmd)
        {
        case EAknCancelGlobalQuery:
            delete iDlg;
            iDlg = NULL;
            QueryDismissedL(EAknSoftkeyCancel);
            return KNullDesC8();
        case EAknMoveDownGlobalListQuery:
            keyEvent.iCode = EKeyDownArrow;
            break;
        case EAknMoveUpGlobalListQuery:
            keyEvent.iCode = EKeyUpArrow;
            break;
        case EAknSelectGlobalListQuery:
            keyEvent.iCode = EKeyOK;
            break;
        default:
            return KNullDesC8();
        }
    iDlg->OfferKeyEventL(keyEvent, eventType);

    return KNullDesC8();
    }

void CAknGlobalListQuerySubject::QueryDismissedL(TInt aResult)
    {
    if (iPending)
        {
        iMessage.Complete(aResult);
        }
        
    iPending = EFalse;
    iReturnVal = NULL;
    
    if (iAppsKeySuppressed)
        {
        ((CAknNotifierAppServerAppUi*)(iStoredEikonEnv->EikAppUi()))->SuppressAppSwitching(EFalse);
        }
    iAppsKeySuppressed = EFalse;
    }

// End of file
