/*
* 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:  ESMR Description (summary) field implementation
 *
*/

#include "cesmrdescriptionfield.h"
#include "mesmrlistobserver.h"
#include "cesmreditor.h"
#include "cesmrrichtextlink.h"
#include "esmrfieldbuilderdef.h"
#include "cesmrfeaturesettings.h"
#include "cesmrglobalnote.h"
#include "nmrlayoutmanager.h"
#include "nmrbitmapmanager.h"
//<cmail>
#include "cesmrurlparserplugin.h"
//</cmail>

#include <calentry.h>
#include <StringLoader.h>
#include <esmrgui.rsg>
#include <AknUtils.h>
#include <AknsBasicBackgroundControlContext.h>
#include <eikmfne.h>

// DEBUG
#include "emailtrace.h"

namespace // codescanner::namespace
    {
    /// Field's component count, iDescription
    const TInt KComponentCount( 1 );
    }//namespace

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

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

// ---------------------------------------------------------------------------
// CESMRDescriptionField::~CESMRDescriptionField
// ---------------------------------------------------------------------------
//
CESMRDescriptionField::~CESMRDescriptionField( )
    {
    FUNC_LOG;
    delete iLocationLink;
    delete iFeatures;
    delete iBgControlContext;
    delete iUrlParser;
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::InitializeL
// ---------------------------------------------------------------------------
//
void CESMRDescriptionField::InitializeL()
    {
    FUNC_LOG;
    // Do nothing
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::InternalizeL
// ---------------------------------------------------------------------------
//
void CESMRDescriptionField::InternalizeL( MESMRCalEntry& aEntry )
    {
    FUNC_LOG;
    CCalEntry& entry = aEntry.Entry ( );
    HBufC* summary = entry.DescriptionL().AllocLC ( );

    // externalize is done only when there is text and its NOT the default one.
    if ( summary->Length ( )> 0 &&
            iDescription->DefaultText().Compare (*summary )!= 0 )
        {
        iDescription->ClearSelectionAndSetTextL ( *summary );
        if ( FeaturesL().FeatureSupported(
                CESMRFeatureSettings::EESMRUIMnFwIntegration ) )
            {
            StoreLinkL( aEntry );
            }
        }

    CleanupStack::PopAndDestroy ( summary );

    // this is needed to be re-called here, otherwise the CEikEdwin
    // does not get correctly instantiated with default text
    iDescription->FocusChanged(EDrawNow);
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::ExternalizeL
// ---------------------------------------------------------------------------
//
void CESMRDescriptionField::ExternalizeL( MESMRCalEntry& aEntry )
    {
    FUNC_LOG;
    HBufC* buf = iDescription->GetTextInHBufL();
    CCalEntry& entry = aEntry.Entry();
    
    if( buf )
        {
        CleanupStack::PushL( buf );

        if( iDescription->DefaultText().Compare( *buf ) != 0 )
            {
            // Edited text. Add link to description text
            HBufC* newBuf = AddLinkToTextL( *buf );
            if( newBuf )
                {
                CleanupStack::PopAndDestroy( buf );
                buf = newBuf;
                CleanupStack::PushL( buf );
                }
            entry.SetDescriptionL( *buf );
            }
        else if ( iLocationLink )
            {
            // Location link set
            entry.SetDescriptionL( iLocationLink->Value() );
            }
        else if ( entry.DescriptionL().Length() != 0 )
            {
            // Clear old description
            entry.SetDescriptionL( KNullDesC );
            }
        CleanupStack::PopAndDestroy( buf );
        }
    else if( iLocationLink )
        {
        entry.SetDescriptionL( iLocationLink->Value() );
        }
    else
        {
        entry.SetDescriptionL( KNullDesC );
        }
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::SetOutlineFocusL
// ---------------------------------------------------------------------------
//
void CESMRDescriptionField::SetOutlineFocusL( TBool aFocus )
    {
    FUNC_LOG;
    CESMRField::SetOutlineFocusL ( aFocus );
    if ( aFocus )
        {
        ChangeMiddleSoftKeyL(EESMRCmdSaveMR,R_QTN_MSK_SAVE);
        }
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::OfferKeyEventL
// ---------------------------------------------------------------------------
//
TKeyResponse CESMRDescriptionField::OfferKeyEventL(const TKeyEvent& aEvent,
        TEventCode aType )
    {
    FUNC_LOG;
    TKeyResponse response( EKeyWasNotConsumed);
    response = iDescription->OfferKeyEventL( aEvent, aType );

    if ( aType == EEventKey &&
         ( aEvent.iScanCode != EStdKeyUpArrow &&
          aEvent.iScanCode != EStdKeyDownArrow ))
        {
        iDescription->DrawDeferred();
        }

    return response;
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::HandleEdwinSizeEventL
// ---------------------------------------------------------------------------
//
TBool CESMRDescriptionField::HandleEdwinSizeEventL(CEikEdwin* /*aEdwin*/,
        TEdwinSizeEvent /*aType*/, TSize aSize )
    {
    FUNC_LOG;
    if ( aSize != iSize )
        {
        iSize = aSize;

        if ( iObserver )
            {
            iObserver->ControlSizeChanged ( this );
            }

        if( iDescription->LineCount() != iLineCount )
            {
            // Line count has changed, the whole component needs
            // to be redrawn
            DrawDeferred();

            // Also if new line count is less than previous one, we
            // need to redraw the parent also (this is the last field).
            // Otherwise the removed line will remain on the screen
            // until parent is redrawn.
            if( iDescription->LineCount() < iLineCount )
                {
                Parent()->DrawDeferred();
                }
            iLineCount = iDescription->LineCount();
            }
        }

    return ETrue;
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::HandleEdwinEventL
// ---------------------------------------------------------------------------
//
void CESMRDescriptionField::HandleEdwinEventL(
        CEikEdwin* aEdwin,TEdwinEvent aEventType)
    {
    FUNC_LOG;
    if ( aEdwin == iDescription
         && aEventType == EEventTextUpdate )
        {
        HBufC* text = iDescription->GetTextInHBufL();
        if ( text )
            {
            CleanupStack::PushL( text );
            TInt textLength( text->Length() );
            if ( iDescription->GetLimitLength() <= textLength )
                {
                NotifyEventAsyncL( EESMRCmdSizeExceeded );
                }
            CleanupStack::PopAndDestroy( text );
            }
        }
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::CESMRDescriptionField
// ---------------------------------------------------------------------------
//
CESMRDescriptionField::CESMRDescriptionField()
    {
    FUNC_LOG;
    SetFieldId( EESMRFieldDescription );
    SetFocusType( EESMRHighlightFocus );
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::ConstructL
// ---------------------------------------------------------------------------
//
void CESMRDescriptionField::ConstructL()
    {
    FUNC_LOG;
    iDescription = CESMREditor::NewL( this, 1, KTextLimit,
                                    CEikEdwin::EResizable |
                                    CEikEdwin::EAvkonEditor );
    iDescription->SetEdwinSizeObserver( this );
    iDescription->SetEdwinObserver( this );
    CESMRField::ConstructL( iDescription );

    HBufC* buf = StringLoader::LoadLC( R_QTN_MEET_REQ_DETAILS_FIELD );
    iDescription->SetDefaultTextL( buf ); // ownership transferred
    CleanupStack::Pop( buf );

    // Setting background instead of theme skin
    NMRBitmapManager::TMRBitmapStruct bitmapStruct;
    bitmapStruct = NMRBitmapManager::GetBitmapStruct( NMRBitmapManager::EMRBitmapInputCenter );

    TRect initialisationRect( 0, 0, 0, 0 );
    iBgControlContext = CAknsBasicBackgroundControlContext::NewL(
                bitmapStruct.iItemId,
                initialisationRect,
                EFalse );

    iDescription->SetSkinBackgroundControlContextL( iBgControlContext );
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::ListObserverSet
// ---------------------------------------------------------------------------
//
void CESMRDescriptionField::ListObserverSet()
    {
    FUNC_LOG;
    iDescription->SetListObserver( iObserver );
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::GetCursorLineVerticalPos
// ---------------------------------------------------------------------------
//
void CESMRDescriptionField::GetCursorLineVerticalPos(TInt& aUpper, TInt& aLower)
    {
    aLower = iDescription->CurrentLineNumber() * iDescription->RowHeight();
    aUpper = aLower - iDescription->RowHeight();
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::StoreLinkL
// ---------------------------------------------------------------------------
//
void CESMRDescriptionField::StoreLinkL( MESMRCalEntry& aEntry )
    {
    FUNC_LOG;
    TPtrC urlPointer;
    TInt position;
    position = UrlParserL().FindLocationUrl( aEntry.Entry().DescriptionL(),
                                           urlPointer );

    if ( position >= KErrNone )
        {
        HBufC* description =
            HBufC::NewL( aEntry.Entry().DescriptionL().Length() );
        CleanupStack::PushL( description );
        TPtr descriptionPointer( description->Des() );
        descriptionPointer.Append( aEntry.Entry().DescriptionL() );
        descriptionPointer.Delete( position, urlPointer.Length() );
        descriptionPointer.TrimLeft();
        if ( description->Length() != 0 )
            {
            iDescription->ClearSelectionAndSetTextL( *description );
            }
        else
            {
            iDescription->ClearSelectionAndSetTextL(
                    iDescription->DefaultText() );
            }
        CleanupStack::PopAndDestroy( description );

        if ( iLocationLink )
            {
            delete iLocationLink;
            iLocationLink = NULL;
            }
        HBufC* showOnMapBuf =
            StringLoader::LoadLC( R_MEET_REQ_LINK_SHOW_ON_MAP );
        iLocationLink = CESMRRichTextLink::NewL( position,
                                     showOnMapBuf->Length(),
                                     urlPointer,
                                     CESMRRichTextLink::ETypeLocationUrl,
                                     CESMRRichTextLink::ETriggerKeyOk );
        CleanupStack::PopAndDestroy( showOnMapBuf );

        StoreGeoValueL( aEntry.Entry(),
                        urlPointer );
        }
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::AddLinkToTextL
// ---------------------------------------------------------------------------
//
HBufC* CESMRDescriptionField::AddLinkToTextL( const TDesC& aBuf )
    {
    FUNC_LOG;
    if( iLocationLink )
        {
        TInt newTextLen = aBuf.Length() + iLocationLink->Value().Length() + 1;
        HBufC* retBuf = HBufC::NewL( newTextLen );

        retBuf->Des().Append( iLocationLink->Value() );
        _LIT( KParagraphSeparator, "\x2029" ); // unicode paragraph separator
        // add the separator after url
        retBuf->Des().Append( KParagraphSeparator );
        retBuf->Des().Append( aBuf );

        return retBuf;
        }
    else
        {
        return NULL;
        }
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::FeaturesL
// ---------------------------------------------------------------------------
//
CESMRFeatureSettings& CESMRDescriptionField::FeaturesL()
    {
    FUNC_LOG;
    if ( !iFeatures )
        {
        iFeatures = CESMRFeatureSettings::NewL();
        }

    return *iFeatures;
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::ExecuteGenericCommandL
// ---------------------------------------------------------------------------
//
TBool CESMRDescriptionField::ExecuteGenericCommandL(
        TInt aCommand )
    {
    FUNC_LOG;
    TBool isUsed( EFalse );
    if ( EESMRCmdSizeExceeded == aCommand )
        {
        CESMRGlobalNote::ExecuteL(
                CESMRGlobalNote::EESMRCannotDisplayMuchMore );

        HBufC* text = iDescription->GetTextInHBufL();
        CleanupDeletePushL( text );
        if ( text )
            {
            TInt curPos = iDescription->CursorPos();
            if( curPos > iDescription->GetLimitLength() - 1 )
                curPos = iDescription->GetLimitLength() - 1;
            HBufC* newText =
                text->Des().Mid( 0,
                        iDescription->GetLimitLength() - 1 ).AllocLC();

            iDescription->SetTextL ( newText );
            CleanupStack::PopAndDestroy( newText );
            newText = NULL;

            iDescription->SetCursorPosL (curPos, EFalse );
            iDescription->HandleTextChangedL();
            iDescription->UpdateScrollBarsL();
            SetFocus(ETrue);
            }
        CleanupStack::PopAndDestroy( text );
        isUsed = ETrue;
        }
    else if ( EESMRCmdDisableWaypointIcon == aCommand )
        {
        isUsed = ETrue;
        
        // Clear location link
        delete iLocationLink;
        iLocationLink = NULL;
        }
    
    return isUsed;
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::CountComponentControls
// ---------------------------------------------------------------------------
//
TInt CESMRDescriptionField::CountComponentControls() const
    {
    return KComponentCount;
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::ComponentControl
// ---------------------------------------------------------------------------
//
CCoeControl* CESMRDescriptionField::ComponentControl( TInt aInd ) const
    {
    if( aInd == 0 )
        {
        return iDescription;
        }
    return NULL;
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::SizeChanged
// ---------------------------------------------------------------------------
//
void CESMRDescriptionField::SizeChanged()
    {
    TRect rect( Rect() );

    // Optimization: Layouting only when necessary
    if( iFieldRect != rect )
        {
        rect = NMRLayoutManager::GetFieldRowLayoutRect( rect, 1 ).Rect();

        TAknLayoutText editorLayoutText = NMRLayoutManager::GetLayoutText(
                        rect,
                        NMRLayoutManager::EMRTextLayoutMultiRowTextEditor );

        TRect editorRect = editorLayoutText.TextRect();

        TRect bgRect( editorRect );
        // Move focus rect so that it's relative to field's position.
        bgRect.Move( -Position() );
        if( iSize.iHeight > 0 )
            {
            bgRect.SetHeight( iSize.iHeight );
            }
        SetFocusRect( bgRect );

        iDescription->SetRect(
                TRect( editorRect.iTl,
                        TSize( editorRect.Width(), iSize.iHeight ) ) );

        // Set also correct font for description field
        TRAP_IGNORE( iDescription->SetFontL( editorLayoutText.Font() ) );

        iFieldRect = rect;
        }
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::MinimumSize
// ---------------------------------------------------------------------------
//
TSize CESMRDescriptionField::MinimumSize()
    {
    TRect rect( Parent()->Rect() );
    TRect listRect =
        NMRLayoutManager::GetLayoutRect(
                rect,
                NMRLayoutManager::EMRLayoutListArea ).Rect();
    TRect fieldRect =
        NMRLayoutManager::GetFieldLayoutRect( listRect, 1 ).Rect();
    TRect rowRect =
        NMRLayoutManager::GetFieldRowLayoutRect( fieldRect, 1 ).Rect();
    TRect viewerRect =
        NMRLayoutManager::GetLayoutText(
                rowRect,
                NMRLayoutManager::EMRTextLayoutMultiRowTextEditor ).TextRect();

    fieldRect.Resize( 0, iSize.iHeight - viewerRect.Height() );

    return fieldRect.Size();
    }

// ---------------------------------------------------------------------------
// CESMRRepeatUntilField::SetContainerWindowL
// ---------------------------------------------------------------------------
//
void CESMRDescriptionField::SetContainerWindowL(
        const CCoeControl& aContainer )
    {
    CCoeControl::SetContainerWindowL( aContainer );
    iDescription->SetContainerWindowL( aContainer );

    iDescription->SetParent( this );
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::StoreGeoValueL
// ---------------------------------------------------------------------------
//
void CESMRDescriptionField::StoreGeoValueL(
        CCalEntry& aCalEntry,
        const TDesC& aLocationUrl )
    {
    TReal lat, lon;
    CCalGeoValue* geoVal = aCalEntry.GeoValueL();

    if ( !geoVal || ! geoVal->GetLatLong( lat, lon ) )
        {
        // GEO value not set. Convert URL
        geoVal = UrlParserL().CreateGeoValueLC( aLocationUrl );
        aCalEntry.SetGeoValueL( *geoVal );
        CleanupStack::Pop( geoVal );

        NotifyEventL( EESMRCmdEnableWaypointIcon );
        }
    }

// ---------------------------------------------------------------------------
// CESMRDescriptionField::UrlParserL
// ---------------------------------------------------------------------------
//
CESMRUrlParserPlugin& CESMRDescriptionField::UrlParserL()
    {
    if ( !iUrlParser )
        {
        iUrlParser = CESMRUrlParserPlugin::NewL();
        }

    return *iUrlParser;
    }

// EOF
