/*
* Copyright (c) 2005-2007 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:  Image transaction element
*
*/


#include "xnbitmap.h"
#include "xnnewsticker.h"
#include "xntype.h"
#include "xnmenu.h"
#include "xnmenuadapter.h"
#include "xnuiengineappif.h"

#include <imageconversion.h>
#include <gulicon.h>

#include "imagetransactionelement.h"
#include "xmluicontrollerpanic.h"
#include "aixmluiutils.h"
#include "xnuiengineappif.h"

using namespace AiXmlUiController;
using namespace XnImageInterface;
using namespace ContentAccess;

namespace AiXmlUiController
    {

TBool IsNodeVisible( CXnNodeAppIf& aNode )
    {
    CXnProperty* propVisibility = aNode.GetPropertyL( XnPropertyNames::style::common::KVisibility );;

    if( propVisibility )
        {
        const TDesC8& visibility = propVisibility->StringValue();

        if( visibility == XnPropertyNames::style::common::visibility::KHidden )
            {
            return EFalse;
            }    
        }

    CXnProperty* propDisplay = aNode.GetPropertyL( XnPropertyNames::style::common::KDisplay );

    if( propDisplay )
        {
        const TDesC8& display = propDisplay->StringValue();

        if( display == XnPropertyNames::style::common::display::KNone )
            {
            return EFalse;
            }
        }

    CXnProperty* propDisabled = aNode.GetPropertyL( XnPropertyNames::common::KDisabled );

    if( propDisabled )
        {
        const TDesC8& disabled = propDisabled->StringValue();

        if( disabled == XnPropertyNames::KTrue )
            {
            return EFalse;
            }
        }
    return ETrue;
    }
/**
 * Uses CImageDecoder to decode images asynchronously.
 * When decoding is done, it tries to find target and set
 * image into element. Destroys itself at end of RunL method.
 */
class CKamikazeImageDecoder: public CActive
    {
public:
    static CKamikazeImageDecoder* NewL(
            RFile& aFile, const TDesC8& aNodeId, 
            const TDesC8& aNodeNs, TXnUiEngineAppIf& aUiEngine);
    ~CKamikazeImageDecoder();
public:
    /**
     * Start decoding and forget instance. 
     * Destroyes itself.
     */
    void DecodeLD();
private:
    // from CActive
    void DoCancel();
    void RunL();
private:    
    void ConstructL(RFile& aFile, const TDesC8& aNodeId,const TDesC8& aNodeNs);
    CKamikazeImageDecoder(TXnUiEngineAppIf& aUiEngine);
    void SetImageL();
private:
    /**
     * Image decoder. Own.
     */
    CImageDecoder* iDecoder;
    /**
     * Target node id
     */
    HBufC8* iNodeId;
    /**
     * Target node namespace
     */
    HBufC8* iNodeNs;
    /**
     * Provides services to find target
     */
    TXnUiEngineAppIf& iUiEngine;
    /**
     * Icon. Own.
     */
    CGulIcon* iIcon;
    };

CKamikazeImageDecoder* CKamikazeImageDecoder::NewL(
    RFile& aFile, 
    const TDesC8& aNodeId,
    const TDesC8& aNodeNs,
    TXnUiEngineAppIf& aUiEngine)
    {
    CKamikazeImageDecoder* p = new (ELeave)CKamikazeImageDecoder(aUiEngine);
    CleanupStack::PushL(p);
    p->ConstructL(aFile,aNodeId,aNodeNs);
    CleanupStack::Pop(p);
    return p;
    }

CKamikazeImageDecoder::CKamikazeImageDecoder(TXnUiEngineAppIf& aUiEngine):
    CActive(CActive::EPriorityStandard ), iUiEngine(aUiEngine)
    {
    CActiveScheduler::Add( this );
    }

CKamikazeImageDecoder::~CKamikazeImageDecoder()
    {
    Cancel();
    delete iDecoder;
    delete iNodeId;
    delete iNodeNs;
    delete iIcon;
    }

void CKamikazeImageDecoder::ConstructL(
    RFile& aFile, 
    const TDesC8& aNodeId, 
    const TDesC8& aNodeNs)
    {
    // Create new decoder for file
    iDecoder = CImageDecoder::FileNewL( aFile, EView );
    iNodeId = aNodeId.AllocL();
    iNodeNs = aNodeNs.AllocL();
    iIcon = CGulIcon::NewL();
    }

void CKamikazeImageDecoder::DecodeLD()
    {
    TFrameInfo frameInfo = iDecoder->FrameInfo(0);
    CFbsBitmap* bitmap = new( ELeave ) CFbsBitmap;
    iIcon->SetBitmap( bitmap );
    
    User::LeaveIfError( bitmap->Create( frameInfo.iOverallSizeInPixels,
                        frameInfo.iFrameDisplayMode ) );
    
    CFbsBitmap* mask(0);
    if ( frameInfo.iFlags & TFrameInfo::ETransparencyPossible )
        {
        mask = new( ELeave ) CFbsBitmap;
        iIcon->SetMask( mask );
        User::LeaveIfError( mask->Create( frameInfo.iOverallSizeInPixels,
                                          ( ( frameInfo.iFlags & TFrameInfo::EAlphaChannel )
                                          ? EGray256 : EGray2 ) ) );
        }
    
    if(iIcon->Mask())
        {
        iDecoder->Convert( &iStatus, *bitmap, *mask );
        }
    else
        {
        iDecoder->Convert( &iStatus, *bitmap );
        }
    SetActive();
    }

void CKamikazeImageDecoder::DoCancel()
    {
    iDecoder->Cancel();
    }

void CKamikazeImageDecoder::SetImageL()
    {
     
    // Find target
    CXnNodeAppIf* node = iUiEngine.FindNodeByIdL(*iNodeId,*iNodeNs);
    if(!node)
        {
        return;
        }
        
    const TDesC8& type = node->Type()->Type();
    
    if ( type == XnImageInterface::MXnImageInterface::Type() )
        {
        MXnImageInterface* imageIntr = NULL;
        if ( !XnComponentInterface::MakeInterfaceL( imageIntr, *node ) )
            {
            return;
            }
        // Set new bitmaps. Ownership is transferred to MXnImageInterface
        iIcon->SetBitmapsOwnedExternally( ETrue );
        imageIntr->SetContentBitmaps( iIcon->Bitmap(), iIcon->Mask() );
      
        }
    // Menu softkey icons
    else if ( ( ( type == KXnMenuItem || type == KXnMenu ) &&
                IsNodeVisible( *node ) ) ||
              type == XnPropertyNames::softkey::KNodeName )
        {
        CXnNodeAppIf* menuBar = node->ParentL();
        
        XnMenuInterface::MXnMenuInterface::TSoftKeyPosition softkeyPosition = 
            XnMenuInterface::MXnMenuInterface::ELeft;
                    
        CXnProperty* property = 
            node->GetPropertyL( XnPropertyNames::softkey::KTypeAttribute );     
        if ( property && property->StringValue() == XnPropertyNames::softkey::type::KRight )
            {
            softkeyPosition = XnMenuInterface::MXnMenuInterface::ERight;
            }
        else if ( property && property->StringValue() == XnPropertyNames::softkey::type::KLeft )
            {
            softkeyPosition = XnMenuInterface::MXnMenuInterface::ELeft;
            }
        else  // Image can be published only to RSK or LSK
            {
            return;
            }
            
        XnMenuInterface::MXnMenuInterface* menuIf = NULL;
        
        XnComponentInterface::MakeInterfaceL( menuIf, *menuBar );
        if ( menuIf )
            {
            // Use black mask and preserver aspect ratio
           
            menuIf->SetSoftKeyImageL( iIcon->Bitmap(), 
                                          iIcon->Mask(), 
                                          softkeyPosition, 
                                          node,
                                          ETrue, 
                                          ETrue ); 
            iIcon->SetBitmapsOwnedExternally( ETrue );
            }
        if( menuBar )
            {
            iUiEngine.RefreshMenuL();
            }
        }
        
    }

void CKamikazeImageDecoder::RunL()
    {
    CleanupStack::PushL(this);
    if(iStatus == KErrNone)
        {
        SetImageL();
        iUiEngine.RenderUIL();
        }
    CleanupStack::PopAndDestroy(this);
    }
     
// ======== MEMBER FUNCTIONS ========

CImageTransactionElement::CImageTransactionElement(
                                AiUtility::CContentPriorityMap& aContentPriorityMap)
    : CTransactionElement(aContentPriorityMap)
    {
    }

CImageTransactionElement* CImageTransactionElement::NewL(
                                AiUtility::CContentPriorityMap& aContentPriorityMap)
    {
    CImageTransactionElement* self = new( ELeave ) CImageTransactionElement(
                                                            aContentPriorityMap );
    return self;
    }

CImageTransactionElement::~CImageTransactionElement()
    {
    delete iNewIcon;
    delete iImageDecoder;
    }

void CImageTransactionElement::InitializeL( CXnNodeAppIf& aTarget,
                                            CGulIcon* aIcon )
    {
    CheckTypeL( aTarget );
    
    LeaveIfNull( aIcon, KErrArgument );
    
    SetTarget( aTarget );
    iNewIcon = aIcon;
    }

void CImageTransactionElement::InitializeL( CXnNodeAppIf& aTarget,
                                            RFile& aFile )
    {
    CheckTypeL( aTarget );
   
    const TDesC8* nodeId = &KNullDesC8;
    
    CXnProperty* property = aTarget.GetPropertyL(XnPropertyNames::common::KId);
    if(property)
        {
        nodeId = &property->StringValue();
        }
    if ( iImageDecoder )
        {
        delete iImageDecoder;
        iImageDecoder = NULL;
        }
    iImageDecoder = CKamikazeImageDecoder::NewL(
                        aFile,*nodeId,aTarget.Namespace(),*aTarget.UiEngineL()); 
    
    SetTarget( aTarget );
    }


void CImageTransactionElement::UpdateDataL()
    {
    if ( iImageDecoder )
        {
        iImageDecoder->DecodeLD();
        iImageDecoder = NULL; // self destroy
        }
    else
        {
        __ASSERT_DEBUG( iNewIcon, Panic( EBitmapNull ) );
    
        const TDesC8& type = LeaveIfNull( Target().Type(), KErrNotSupported )->Type();
        
        if ( type == XnImageInterface::MXnImageInterface::Type() )
            {
            MXnImageInterface* imageIntr = NULL;
            if ( !XnComponentInterface::MakeInterfaceL( imageIntr, Target() ) )
                {
                User::Leave( KErrNotSupported );
                }
            // Set new bitmaps. Ownership is transferred to MXnImageInterface
            iNewIcon->SetBitmapsOwnedExternally( ETrue );
            imageIntr->SetContentBitmaps( iNewIcon->Bitmap(), iNewIcon->Mask() );
            }
        // Menu softkey icons
        else if ( ( ( type == KXnMenuItem || type == KXnMenu ) &&
                    IsNodeVisible( Target() ) ) ||
                  type == XnPropertyNames::softkey::KNodeName )
            {
            CXnNodeAppIf* menuBar = Target().ParentL();
            
            XnMenuInterface::MXnMenuInterface::TSoftKeyPosition softkeyPosition = 
                XnMenuInterface::MXnMenuInterface::ELeft;
                        
            CXnProperty* property = 
                Target().GetPropertyL( XnPropertyNames::softkey::KTypeAttribute );     
            if ( property && property->StringValue() == XnPropertyNames::softkey::type::KRight )
                {
                softkeyPosition = XnMenuInterface::MXnMenuInterface::ERight;
                }
            else if ( property && property->StringValue() == XnPropertyNames::softkey::type::KLeft )
                {
                softkeyPosition = XnMenuInterface::MXnMenuInterface::ELeft;
                }
            else  // Image can be published only to RSK or LSK
                {
                delete iNewIcon;
                iNewIcon = NULL;            
                User::Leave( KErrNotSupported );
                }
                
            XnMenuInterface::MXnMenuInterface* menuIf = NULL;
            
            XnComponentInterface::MakeInterfaceL( menuIf, *menuBar );
            if ( menuIf )
                {
                // Use black mask and preserver aspect ratio
                TRAPD(err,
                    menuIf->SetSoftKeyImageL( iNewIcon->Bitmap(), 
                                              iNewIcon->Mask(), 
                                              softkeyPosition, 
                                              &Target(),
                                              ETrue, 
                                              ETrue ) 
                );
                // Menuinterface takes ownership
                if ( err == KErrNone )
                    {
                    iNewIcon->SetBitmapsOwnedExternally( ETrue );
                    }
                if( menuBar )
                    {
                    menuBar->UiEngineL()->RefreshMenuL();
                    }
                }
            }
        else
            {
            User::Leave( KErrNotSupported );
            }
        }
    
    delete iNewIcon;
    iNewIcon = NULL;
    
    UpdateContentPriorityL();
    }

void CImageTransactionElement::Reset()
    {
    if ( iImageDecoder )
        {
        delete iImageDecoder;
        iImageDecoder = NULL;
        }
    
    CTransactionElement::Reset();

    delete iNewIcon;
    iNewIcon = NULL;
    }

TBool CImageTransactionElement::IsSupported( CXnNodeAppIf& aTarget )
    {
    // Get type info
    CXnType* typeInfo = aTarget.Type();
    
    if ( !typeInfo )
        {
        return EFalse;
        }
    
    const TDesC8& type = typeInfo->Type();
    
    // image element and newsticker supported
    return ( type == XnImageInterface::MXnImageInterface::Type() ||
             type == XnNewstickerInterface::MXnNewstickerInterface::Type() ||
             type == XnMenuInterface::MXnMenuInterface::Type() ||
             type == KXnMenuItem ||
             type == KXnMenu ||
             type == XnPropertyNames::softkey::KNodeName );
    }

void CImageTransactionElement::CheckTypeL( CXnNodeAppIf& aTarget )
    {
    if ( !IsSupported( aTarget ) )
        {
        User::Leave( KErrNotSupported );
        }
    }
} // ns
