/*
* Copyright (c) 2004 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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:  Application Ui member definitions.
*
*/



// INCLUDE FILES

#include "PushViewerMsgEdAppUi.h"
#include "PushViewerDoc.h"
#include "PushViewerDef.h"
#include "PushViewerPanic.h"
#include "PushMtmUtil.h"
#include "PushViewer.hrh"
#include "PushMtmLog.h"
#include <push/CSIPushMsgEntry.h>
#include <push/CSLPushMsgEntry.h>
#include <PushViewer.rsg>
#include <aknmessagequerydialog.h>
#include <AknQueryDialog.h>
#include <MsgEditorView.h>
#include <MsgBodyControl.h>
#include <txtrich.h>
#include <txtfrmat.h>
#include <txtfmlyr.h>
#include <gdi.h>
#include <bldvariant.hrh>
#include <eikrted.h>
#include <barsread.h>
#include <AknNoteWrappers.h>
#ifdef __SERIES60_HELP
// Context-Sensitve Help File
#include <hlplch.h>
#include <csxhelp/wpush.hlp.hrh>
#endif // __SERIES60_HELP

#include "eikon.hrh"

// ================= MEMBER FUNCTIONS =======================

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::CPushViewerMsgEdAppUi
// ---------------------------------------------------------
//
CPushViewerMsgEdAppUi::CPushViewerMsgEdAppUi()
    {
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::~CPushViewerMsgEdAppUi
// ---------------------------------------------------------
//
CPushViewerMsgEdAppUi::~CPushViewerMsgEdAppUi()
    {
    PUSHLOG_ENTERFN("CPushViewerMsgEdAppUi::~CPushViewerMsgEdAppUi")
    delete iView;
    iView = NULL;
    delete iContext;
    iContext = NULL;
    PUSHLOG_LEAVEFN("CPushViewerMsgEdAppUi::~CPushViewerMsgEdAppUi")
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::ConstructL
// ---------------------------------------------------------
//
void CPushViewerMsgEdAppUi::ConstructL()
    {
    PUSHLOG_ENTERFN("CPushViewerMsgEdAppUi::ConstructL")

    CMsgEditorAppUi::ConstructL();

    if ( !iEikonEnv->StartedAsServerApp( ) )
        {
        // If the app was not started as server app,
        // we can call PrepareLaunchL
        Document()->PrepareToLaunchL( this );
        }

    PUSHLOG_LEAVEFN("CPushViewerMsgEdAppUi::ConstructL")
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::ConstructBodyTextL
// ---------------------------------------------------------
//
TInt CPushViewerMsgEdAppUi::ConstructBodyTextL
    ( CMsgBodyControl& aBodyControl1, CMsgBodyControl& aBodyControl2 ) const
    {
    PUSHLOG_ENTERFN("CPushViewerMsgEdAppUi::ConstructBodyTextL");

    HBufC* staticText = iEikonEnv->AllocReadResourceLC
                        ( R_PUSHVIEWER_MAINPANE_TEXT );

    TPtrC renderedTextPtr( *staticText ); // Static text by default.
    TPtrC renderedHrefPtr( KNullDesC );

    if ( Model().PushMsgType() == KUidWapPushMsgSI.iUid )
        {
        CSIPushMsgEntry* si = STATIC_CAST( CSIPushMsgEntry*, &Model() );

        const TPtrC text = si->Text();
        if ( text.Length() )
            {
            renderedTextPtr.Set( text );
            }
        else
            {
            renderedTextPtr.Set( *staticText );
            }

        const TPtrC url = si->Url();
        if ( url.Length() )
            {
            renderedHrefPtr.Set( url );
            }
        }
    else if ( Model().PushMsgType() == KUidWapPushMsgSL.iUid )
        {
        CSLPushMsgEntry* sl = STATIC_CAST( CSLPushMsgEntry*, &Model() );

        const TPtrC url = sl->Url();
        if ( url.Length() )
            {
            renderedHrefPtr.Set( url );
            }
        }
    else
        {
        User::Leave( KErrNotSupported );
        }

    // The message goes to the first body control by default, but
    // if it does not fit into one screen, then first comes the href.

    aBodyControl1.InsertTextL( renderedTextPtr );

    CMsgBodyControl* controlContainingTheUrl = NULL;
    TInt indexOfHrefControl = KErrNotFound;

    // Add the href
    if ( renderedHrefPtr.Length() == 0 )
        {
        // No href.
        controlContainingTheUrl = NULL;
        iAvkonAppUi->Cba()->SetCommandSetL( R_PUSHVIEWER_SOFTKEYS );
        iAvkonAppUi->Cba()->DrawNow();
        }
    else
        {
        aBodyControl2.InsertTextL( renderedHrefPtr );
        controlContainingTheUrl = &aBodyControl2;
        indexOfHrefControl = 1; // Zero based.
        }

    aBodyControl1.SetPlainTextMode( ETrue );
    aBodyControl2.SetPlainTextMode( ETrue );

    // Switch on URL highlighting. We use FindItem for it -
    // otherwise Find Item has no other role!
    if ( controlContainingTheUrl != NULL )
        {
        if ( controlContainingTheUrl->ItemFinder() )
            {
            controlContainingTheUrl->
                ItemFinder()->SetFindModeL( CItemFinder::EUrlAddress );
            controlContainingTheUrl->
                SetupAutomaticFindAfterFocusChangeL( ETrue );
            }
        controlContainingTheUrl->Editor().SetAlignment( EAknEditorAlignCenter );
        }

    CleanupStack::PopAndDestroy( staticText ); // staticText

    PUSHLOG_LEAVEFN("CPushViewerMsgEdAppUi::ConstructBodyTextL");
    return indexOfHrefControl;
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::ConstructViewL
// ---------------------------------------------------------
//
void CPushViewerMsgEdAppUi::ConstructViewL()
    {
    CMsgEditorView* newView = CMsgEditorView::NewL
                              ( *this, CMsgEditorView::EMsgReadOnly );
    delete iView;
    iView = newView;

    // Let two body controls: one for the message text and one for the Href

    // There is already one by default - get a pointer to it.
    CMsgBodyControl* bodyControl1 = REINTERPRET_CAST( CMsgBodyControl*,
                                    iView->ControlById( EMsgComponentIdBody ) );

    // Create the second:
    CMsgBodyControl* bodyControl2 = CMsgBodyControl::NewL( iView );
    CleanupStack::PushL( bodyControl2 );
    iView->AddControlL( bodyControl2,
                        /*aControlId*/EMyMsgComponentIdBody,
                        /*aIndex*/1,
                        /*aFormComponent*/EMsgBody );
    CleanupStack::Pop( bodyControl2 ); // bodyControl2

    TInt indexOfHrefControl = ConstructBodyTextL( *bodyControl1, *bodyControl2 );

    // Construct the view.
    TInt controlIdForFocus = indexOfHrefControl==1?EMyMsgComponentIdBody:EMsgComponentIdBody;
    iView->ExecuteL( ClientRect(), controlIdForFocus );
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::HandleKeyEventL
// ---------------------------------------------------------
//
TKeyResponse CPushViewerMsgEdAppUi::HandleKeyEventL
                                    ( const TKeyEvent& aKeyEvent,
                                      TEventCode aType )
    {
    PUSHLOG_WRITE_FORMAT
        ("CPushViewerMsgEdAppUi::HandleKeyEventL <%d>",aKeyEvent.iCode)
    // Check for iView and iContext objects are created before Handle
    if ( (NULL == iView) || (NULL == iContext) )
        {
        return (EKeyWasConsumed);
        }

    if ( aType == EEventKey )
        {
        switch ( aKeyEvent.iCode )
            {

            case EKeyDevice3:
                {
                // Selection key pressed. Behave as "Load service" if there is
                // service to download.
                const TMsvEntry& context = Model().Entry();
                if ( CPushMtmUtil::Attrs( context ) & EPushMtmAttrHasHref )
                    {
                    HandleCommandL( EPushViewerCmdLoadService );
                    }
                break;
                }

            case EKeyLeftUpArrow:         // Northwest
            case EStdKeyDevice10:         //   : Extra KeyEvent supports diagonal event simulator wedge
            case EKeyLeftArrow:           // West
            case EKeyLeftDownArrow:       // Southwest
            case EStdKeyDevice13:         //   : Extra KeyEvent supports diagonal event simulator wedge
                {
                HandleCommandL( EPushViewerCmdPreviousMessage );
                break;
                }

            case EKeyRightUpArrow:        // Northeast
            case EStdKeyDevice11:         //   : Extra KeyEvent supports diagonal event simulator wedge
            case EKeyRightArrow:          // East
            case EKeyRightDownArrow:      // Southeast
            case EStdKeyDevice12:         //   : Extra KeyEvent supports diagonal event simulator wedge
                {
                HandleCommandL( EPushViewerCmdNextMessage );
                break;
                }

            case EKeyBackspace :
                {
                CAknQueryDialog* dlg = CAknQueryDialog::NewL();
                if ( dlg->ExecuteLD
                    ( R_PUSHVIEWER_ENTRY_DELETE_CONFIRM ) == EAknSoftkeyYes )
                    {
                    DeleteAndExitL();
                    }
                break;
                }

            default:
                {
                iView->OfferKeyEventL( aKeyEvent, aType );
                break;
                }

            }
        }

    return EKeyWasConsumed;
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::DynInitMenuPaneL
// ---------------------------------------------------------
//
void CPushViewerMsgEdAppUi::DynInitMenuPaneL( TInt aMenuId,
                                         CEikMenuPane* aMenuPane )
    {
    if ( aMenuId == R_PUSHVIEWER_OPTIONS_MENU_PANE )
        {
        // Remove EPushViewerCmdLoadService if the current message
        // does not contain URL.
        CPushMsgEntryBase& modelBase = Model();
        if ( Model().PushMsgType() == KUidWapPushMsgSI.iUid )
            {
            CSIPushMsgEntry& si = (CSIPushMsgEntry&)modelBase;
            if ( !si.Url().Length() )
                {
                aMenuPane->DeleteMenuItem( EPushViewerCmdLoadService );
                Cba()->SetCommandSetL( R_PUSHVIEWER_SOFTKEYS );
                }
            }
        else if ( Model().PushMsgType() == KUidWapPushMsgSL.iUid )
            {
            CSLPushMsgEntry& sl = (CSLPushMsgEntry&)modelBase;
            __ASSERT_DEBUG( sl.Url().Length() != 0,
                            ViewerPanic( EPushViewerPanSlEmptyHref ) );
            if ( !sl.Url().Length() )
                {
                aMenuPane->DeleteMenuItem( EPushViewerCmdLoadService );
                Cba()->SetCommandSetL( R_PUSHVIEWER_SOFTKEYS );
                }
            }
        }
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::Model
// ---------------------------------------------------------
//
CPushMsgEntryBase& CPushViewerMsgEdAppUi::Model() const
    {
    PUSHLOG_WRITE_FORMAT("CPushViewerMsgEdAppUi::Model <%x>",iContext)
    return *iContext;
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::PushDoc
// ---------------------------------------------------------
//
CPushViewerDocument& CPushViewerMsgEdAppUi::PushDoc() const
    {
    PUSHLOG_ENTERFN("CPushViewerMsgEdAppUi::PushDoc")
    return REINTERPRET_CAST( CPushViewerDocument&, *Document() );
    PUSHLOG_LEAVEFN("CPushViewerMsgEdAppUi::PushDoc")
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::UpdateNaviPaneL
// ---------------------------------------------------------
//
void CPushViewerMsgEdAppUi::UpdateNaviPaneL()
    {
    PUSHLOG_ENTERFN("CPushViewerMsgEdAppUi::UpdateNaviPaneL")

    CEikImage* image = new (ELeave) CEikImage;
    CleanupStack::PushL( image );

    // Read image from resource.
    //
    TResourceReader reader;
    iCoeEnv->CreateResourceReaderLC( reader, R_PUSHVIEWER_NAVI_IMAGE );
    image->ConstructFromResourceL( reader );
    CleanupStack::PopAndDestroy(); // reader

    CMsgEditorAppUi::UpdateNaviPaneL( image->Bitmap(), image->Mask() );
    image->SetPictureOwnedExternally( ETrue );

    CleanupStack::PopAndDestroy(); // image

    PUSHLOG_LEAVEFN("CPushViewerMsgEdAppUi::UpdateNaviPaneL")
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::IsExpired
// ---------------------------------------------------------
//
TBool CPushViewerMsgEdAppUi::IsExpired()
    {
    TBool ret( EFalse );

    if ( Document()->Entry().iBioType == KUidWapPushMsgSI.iUid )
        {
        CSIPushMsgEntry* si = STATIC_CAST( CSIPushMsgEntry*, iContext );
        // Check expiration if expiration time was set.
        if ( si->Expires() != Time::NullTTime() )
            {
            TTime today;
            today.UniversalTime();
            if ( si->Expires() < today )
                {
                ret = ETrue;
                }
            }
        }

    return ret;
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::DoMsgSaveExitL
// ---------------------------------------------------------
//
void CPushViewerMsgEdAppUi::DoMsgSaveExitL()
    {
    PUSHLOG_ENTERFN("CPushViewerMsgEdAppUi::DoMsgSaveExitL");

    Exit( EAknSoftkeyBack );

    PUSHLOG_LEAVEFN("CPushViewerMsgEdAppUi::DoMsgSaveExitL")
    };

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::NotifyAndExitL
// ---------------------------------------------------------
//
void CPushViewerMsgEdAppUi::NotifyAndExitL( TInt aResId )
    {
    PUSHLOG_ENTERFN("CPushViewerMsgEdAppUi::NotifyAndExitL");

    HBufC* noteText = iCoeEnv->AllocReadResourceLC( aResId );
    CAknInformationNote* note = new (ELeave) CAknInformationNote( ETrue );
    note->ExecuteLD( *noteText );
    CleanupStack::PopAndDestroy( noteText ); // noteText

    // Close the application.
    if ( !IsAppShutterRunning() )
        {
        PUSHLOG_WRITE(" RunAppShutter")
        RunAppShutter();
        }

    PUSHLOG_LEAVEFN("CPushViewerMsgEdAppUi::NotifyAndExitL");
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::LaunchViewL
// ---------------------------------------------------------
//
void CPushViewerMsgEdAppUi::LaunchViewL()
    {
    __ASSERT_ALWAYS( Document()->Entry().iMtm == KUidMtmWapPush,
                     ViewerPanic( EPushViewerPanBadMtmType ) );

    // Construct model.
    CPushMsgEntryBase* newContext = NULL;
    const TInt32 bioType( Document()->Entry().iBioType );

    if ( bioType == KUidWapPushMsgSI.iUid )
        {
        newContext = CSIPushMsgEntry::NewL();
        }
    else if ( bioType == KUidWapPushMsgSL.iUid )
        {
        newContext = CSLPushMsgEntry::NewL();
        }
    else if ( bioType == KUidWapPushMsgMultiPart.iUid )
        {
#ifdef __TEST_MULTIPART_SUPP
        newContext = CMultiPartPushMsgEntry::NewL();
#else // __TEST_MULTIPART_SUPP
        User::Leave( KErrNotSupported );
#endif // __TEST_MULTIPART_SUPP
        }
    else
        {
        __ASSERT_DEBUG( EFalse, ViewerPanic( EPushViewerPanBadPushType ) );
        User::Leave( KErrNotSupported );
        }

    CleanupStack::PushL( newContext );
    newContext->RetrieveL( Document()->Session(), Document()->Entry().Id() );
    delete iContext;
    iContext = NULL;
    iContext = newContext;
    CleanupStack::Pop( newContext ); // newContext

    // Construct view.
    UpdateNaviPaneL();
    ConstructViewL();
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::HandleEntryChangeL
// ---------------------------------------------------------
//
void CPushViewerMsgEdAppUi::HandleEntryChangeL()
    {
    PUSHLOG_ENTERFN("CPushViewerMsgEdAppUi::HandleEntryChangeL");


    // We have to act only in case of such changes where the content
    // of the message changes, not only the unread/read flag.
    // The content handlers and the Push subsystem behave so that
    // the content is changed only when the entry becomes 'unread',
    // except one case where the CH changes the content, but the
    // message becomes 'read' (SL-execute-high). In this case
    // a flag indicates that the content was changed.

    // Get an up-to-date entry and check the necessary flags:
    TMsvEntry tEntry;
    TMsvId service;
    TMsvId entryId = Document()->Entry().Id();
    CMsvSession& msvSession = Document()->Session();
    User::LeaveIfError( msvSession.GetEntry( entryId, service, tEntry ) );
    TBool isChangeToUnread = tEntry.Unread();
    TBool contentChangedFlagSet =
          CPushMtmUtil::Attrs( tEntry ) & EPushMtmReadButContentChanged;

    if ( !isChangeToUnread && !contentChangedFlagSet )
        {
        // Nothing to do. Somebody just set it as read.
        PUSHLOG_WRITE(" Content not changed");
        }
    else
        {
        // Show note about the message changes & close the application.
        NotifyAndExitL( R_PUSHVIEWER_INFO_REPLACED );
        }

    PUSHLOG_LEAVEFN("CPushViewerMsgEdAppUi::HandleEntryChangeL")
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::HandleEntryDeletedL
// ---------------------------------------------------------
//
void CPushViewerMsgEdAppUi::HandleEntryDeletedL()
    {
    PUSHLOG_ENTERFN("CPushViewerMsgEdAppUi::HandleEntryDeletedL");
    // Check for iView and iContext objects are created before Handle
    if ( (NULL == iView) || (NULL == iContext))
        {
        return;
        }
    // Show note about the message deletion & close the application.
    NotifyAndExitL( R_PUSHVIEWER_INFO_DELETED );

    PUSHLOG_LEAVEFN("CPushViewerMsgEdAppUi::HandleEntryDeletedL")
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::GetHelpContextForControl
// ---------------------------------------------------------
//
void CPushViewerMsgEdAppUi::GetHelpContextForControl
                           ( TCoeHelpContext& /*aContext*/ ) const
    {
    }

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::HandleCommandL
// See DynInitMenuPaneL() to see which commands are valid
// on a given type of item.
// ---------------------------------------------------------
//
void CPushViewerMsgEdAppUi::HandleCommandL( TInt aCommand )
    {
    PUSHLOG_WRITE_FORMAT("CPushViewerMsgEdAppUi::HandleCommandL <%d>",aCommand)
    // Check for iView and iContext objects are created before Handle
    if ( (NULL == iView) || (NULL == iContext))
        {
        return;
        }
    switch ( aCommand )
        {
        case EPushViewerCmdLoadService:
            {
            if ( IsExpired() )
                {
                // The entry is expired.
                HBufC* value =
                    iCoeEnv->AllocReadResourceLC( R_PUSHVIEWER_EXPIRED_NOTE );
                CAknInformationNote* note =
                    new (ELeave) CAknInformationNote( ETrue );
                note->ExecuteLD( *value );
                CleanupStack::PopAndDestroy( value ); // value

                // Delete the expired message and exit.
                DeleteAndExitL();
                }
            else
                {
                PushDoc().IssueLoadServiceL();
                }
            break;
            }

        case EPushViewerCmdDelete:
            {
            CAknQueryDialog* dlg = CAknQueryDialog::NewL();
            if ( dlg->ExecuteLD
                ( R_PUSHVIEWER_ENTRY_DELETE_CONFIRM ) == EAknSoftkeyYes )
                {
                DeleteAndExitL();
                }
            break;
            }

        case EPushViewerCmdMessageInfo:
            {
            PushDoc().IssueMessageInfoL();
            break;
            }

        case EPushViewerCmdPreviousMessage:
            {
            if ( IsNextMessageAvailableL( EFalse ) )
                {
                NextMessageL( EFalse );
                }
            break;
            }

        case EPushViewerCmdNextMessage:
            {
            if ( IsNextMessageAvailableL( ETrue ) )
                {
                NextMessageL( ETrue );
                }
            break;
            }

#ifdef __SERIES60_HELP

        case EPushViewerCmdHelp:
            {
            HlpLauncher::LaunchHelpApplicationL
                ( iEikonEnv->WsSession(), AppHelpContextL() );
            break;
            }

#endif //__SERIES60_HELP

        case EPushViewerCmdBack:
        case EPushViewerCmdExit:
            {
            DoMsgSaveExitL();
            break;
            }

        default:
            {
            break;
            }
        }
    }

#ifdef __SERIES60_HELP

// ---------------------------------------------------------
// CPushViewerMsgEdAppUi::HelpContextL
// ---------------------------------------------------------
//
CArrayFix<TCoeHelpContext>* CPushViewerMsgEdAppUi::HelpContextL() const
    {
    CArrayFix<TCoeHelpContext>* contexts = new (ELeave) CArrayFixFlat<TCoeHelpContext>( 1 );
    CleanupStack::PushL( contexts );
    TCoeHelpContext help( TUid::Uid( EUidPushViewerApp ), KWPUSH_HLP_VIEWER );
    contexts->AppendL( help );
    CleanupStack::Pop(); // contexts
    return contexts;
    }

#endif // __SERIES60_HELP

// End of file.

