/*
* 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: 
*      View images popup dialog listbox
*      
*
*/


// INCLUDES
#include "BrowserViewImagesListBox.h"
#include "BrowserDialogsProviderConstants.h"

#include <gulicon.h>
#include <e32math.h>
#include <akniconarray.h>
#include <Oma2Agent.h>
using namespace ContentAccess;
//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::CBrowserViewImagesListBox
// 
//  EPOC first phase Constructor - must not leave
//-----------------------------------------------------------------------------
//
CBrowserViewImagesListBox::CBrowserViewImagesListBox( )
                        : CAknDoubleLargeGraphicPopupMenuStyleListBox(), 
                        iFormat(), 
                        iCodec(), 
                        iDRMOutputBuf(NULL),
                        iImageIndex(0)
    {
    iRetryingConvert = EFalse;
    }


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::~CBrowserViewImagesListBox
// 
//  Destructor
//-----------------------------------------------------------------------------
//
CBrowserViewImagesListBox::~CBrowserViewImagesListBox()
    {
    delete [] iDRMOutputBuf;
    delete iConverter;
    delete iCurrentBitmap;
    }

//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::ConstructL( 
//                                CCoeControl& aParent, 
//                                CArrayFixFlat<TBrCtlImageCarrier>& aImages )
// 
//  Second Phase constructor
//-----------------------------------------------------------------------------
//
void CBrowserViewImagesListBox::ConstructL( 
                                CCoeControl& aParent, 
                                CArrayFixFlat<TBrCtlImageCarrier>& aImages )
    {
    iImages = &aImages;
    
    CAknDoubleLargeGraphicPopupMenuStyleListBox::ConstructL( &aParent, 0 );

    iConverter = CMdaImageDescToBitmapUtility::NewL( *this );

    iIcons = new( ELeave) CAknIconArray( 5 );       // iIcons must not be deleted in destructor! 

    // create placeholder icon
    CGulIcon* icon = CreatePlaceholderIconL();
    CleanupStack::PushL(icon);
    iIcons->AppendL(icon);
    CleanupStack::Pop();    // icon

    ItemDrawer()->ColumnData()->SetIconArray( iIcons );   // iIcons NOT DELETED IN DESTRUCTOR!!!

    // ---------------------------------------------------------------------------------
    // items

    iItemList = STATIC_CAST(CDesCArray*, Model()->ItemTextArray());     // MUST NOT BE DELETED IN DESTRUCTOR

    TBuf<KMaxAltTextLength> buf;
    TInt cstart = 0;
    TInt cend = 0;
    
    // append items with placeholder thumbnail
    for(TInt i=0; i<iImages->Count(); i++)
        {
        buf = _L("0\t");
        TBrCtlImageCarrier& img = iImages->At(i);
        
        if( img.AltText().Length() > 0 )
            {            
            buf.Append(img.AltText().Left( buf.MaxLength() - buf.Length() ) );
            }
        else
            {
            //get filename w/o extension from url
            cstart = img.Url().LocateReverse('/') + 1;
            cend   = img.Url().LocateReverse('.');
            if ( cend <= cstart ) cend = img.Url().Length();
                {
                buf.Append( img.Url().Mid 
                    ( cstart, 
                            ( cend - cstart ) < ( buf.MaxLength() - buf.Length() ) 
                                ?
                            ( cend - cstart ) 
                                :
                            ( buf.MaxLength() - buf.Length() )
            	        ) 
                    );
                }
            }
            
        iItemList->AppendL(buf);
        }
        
    ItemDrawer()->ColumnData()->EnableMarqueeL( ETrue );
    }


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::CurrentlySelectedImage()
//-----------------------------------------------------------------------------
//
const TBrCtlImageCarrier& CBrowserViewImagesListBox::CurrentlySelectedImage()
    {
    return iImages->At( CurrentItemIndex() );
    }


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::CreatePlaceholderIconL()
//-----------------------------------------------------------------------------
//
CGulIcon* CBrowserViewImagesListBox::CreatePlaceholderIconL()
    {
    CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
    CleanupStack::PushL(bitmap);
    if(KErrNone != bitmap->Create(TSize(42,32), EColor16M))
        User::Leave(KErrNoMemory);

    // create icon
    CGulIcon* icon = CGulIcon::NewL(bitmap); // bitmap is owned, no mask used
    CleanupStack::Pop();    // bitmap
    return icon;
    }


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::Fit()
//-----------------------------------------------------------------------------
//
TSize CBrowserViewImagesListBox::Fit( const TSize& aSrc, const TSize& aTgt )
    {
    TSize result1(aTgt);
    TSize result2(aTgt);

    TInt dA( aTgt.iWidth - aSrc.iWidth );
    TInt dB( aTgt.iHeight - aSrc.iHeight );
    TReal tmp = aSrc.iHeight + ((TReal)(aSrc.iHeight * dA) / (TReal)aSrc.iWidth);
    TReal res;
    Math::Round( res, tmp, 0);
    result1.iHeight = (TInt)res;
    tmp = aSrc.iWidth + ((TReal)(aSrc.iWidth * dB) / (TReal)aSrc.iHeight);
    Math::Round( res, tmp, 0);
    result2.iWidth = (TInt)res;

    TSize result;
    if(result1.iWidth <= aTgt.iWidth && result1.iHeight <= aTgt.iHeight)
        result = result1;
    else
        result = result2;

    return result;    
    }


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::CreateIconL(
//                                      CFbsBitmap* aBitmap, TBool aShrinkIt )
//-----------------------------------------------------------------------------
//
CGulIcon* CBrowserViewImagesListBox::CreateIconL(
                                        CFbsBitmap* aBitmap, TBool aShrinkIt)
    {
    CGulIcon* icon = NULL;

    // create icon
    if(aShrinkIt)
        {
        CFbsBitmap* bmp = new(ELeave)CFbsBitmap;
        CleanupStack::PushL(bmp);
        User::LeaveIfError(bmp->Create(TSize(42,32), EColor16M));
    
        // create bitmap device
        CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(bmp);
        CleanupStack::PushL(dev);
    
        // create graphics context for bitmap device
        CGraphicsContext* ctx = NULL;
        User::LeaveIfError( dev->CreateContext(ctx) );
        CleanupStack::PushL(ctx);
    
        // calculate aspect ratio
        TSize targetSize = Fit(aBitmap->SizeInPixels(), bmp->SizeInPixels());
        // copy bitmap to temporary bitmap
        ctx->DrawBitmap(TRect(TPoint(0,0), targetSize), aBitmap, TRect(TPoint(0,0), aBitmap->SizeInPixels()));

        CleanupStack::PopAndDestroy(2);   // ctx, dev

        icon = CGulIcon::NewL(bmp); // bmp is owned, no mask used
        CleanupStack::Pop();  // bmp
        delete aBitmap;
        } 
    else 
        {
        icon = CGulIcon::NewL(aBitmap); // bitmap is owned, no mask used
        }

    return icon;
    }


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::StartConversionL()
//-----------------------------------------------------------------------------
//
void CBrowserViewImagesListBox::StartConversionL()
    {
    // if we are out of index, stop
    if (iImageIndex >= iImages->Count())
        {
        // zero non-owned pointers
        iCurrentBitmap = NULL;
        iIcons = NULL;
        iItemList = NULL;

        // delete converter because it is not needed anymore
        delete iConverter;
        iConverter = NULL;
        return;
        }

    // begin open
    TBrCtlImageCarrier& img = iImages->At( iImageIndex );
    
    if ( img.ImageType() == EImageTypeWbmp )
        {
        iConverter->OpenL( img.RawData(), &iFormat, &iCodec );
        }
    else if ( img.ImageType() == EImageTypeOta )
        {
        iConverter->OpenL( img.RawData(), &iFormat, &iCodec );
        }
    else
        {
        iConverter->OpenL( img.RawData() );        
        }
    // MiuoOpenComplete will be called next
    }


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::MiuoConvertComplete( TInt aError )
//-----------------------------------------------------------------------------
//
void CBrowserViewImagesListBox::MiuoConvertComplete( TInt aError )
    {
    TRAPD(err, MiuoConvertCompleteL(aError));
    if(err!=KErrNone)
        {
        DeleteCurrentBitmap();
        TRAP(err, ConvertNextImageL());
        }
    }


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::ConvertNextImageL()
//-----------------------------------------------------------------------------
//
void CBrowserViewImagesListBox::ConvertNextImageL()
    {
    // close converter
    iConverter->Close();    
    iImageIndex++;
    StartConversionL();    
    }


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::CreateCurrentBitmapL( TBool aUseBitmapSize )
//-----------------------------------------------------------------------------
//
TInt CBrowserViewImagesListBox::CreateCurrentBitmapL( TBool aUseBitmapSize )
    {
    DeleteCurrentBitmap();  // just in case
    iCurrentBitmap = new(ELeave) CFbsBitmap;

    TInt err = KErrNone;
    if( aUseBitmapSize )
        {
        err = iCurrentBitmap->Create(iFrameInfo.iOverallSizeInPixels, EColor16M);
        }
    else
        {
        // Store the size of the thumbnail
        err = iCurrentBitmap->Create( TSize(42,32), EColor16M);
        }

    return err;
    }


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::MiuoOpenComplete(TInt aError)
//-----------------------------------------------------------------------------
//
void CBrowserViewImagesListBox::MiuoOpenComplete(TInt aError)
    {
    TRAPD(err, MiuoOpenCompleteL(aError));
    if(err!=KErrNone)
        {
        // just in case, delete iCurrentBitmap if MiuoOpenCompleteL left
        // after allocating the bitmap
        DeleteCurrentBitmap();        

        // try to convert next thumbnail image until all have been tried
        // if this fails, placeholders will still remain
        TRAP(err, ConvertNextImageL());
        }
    }


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::MiuoOpenCompleteL( TInt aError )
//-----------------------------------------------------------------------------
//
void CBrowserViewImagesListBox::MiuoOpenCompleteL( TInt aError )
    {
    if(aError==KErrNone)
        {
        iConverter->FrameInfo(0, iFrameInfo);
        // create new current bitmap for conversion
        TInt err = CreateCurrentBitmapL();
        if(err!=KErrNone)
            {
            // unable to create bitmap, so we won't transfer its ownership to iIcons
            // -> delete
            DeleteCurrentBitmap();
            // try next image if available
            ConvertNextImageL();
            }
        else 
            {
            // start converter, MiuoConvertComplete will be called next
            // if this leaves, iCurrentBitmap will remain allocated, but deleted in MiuoOpenComplete
            iConverter->ConvertL(*iCurrentBitmap);
            }
        }
    else 
        {
        TInt error(KErrNone);
        
        // error occurred, we decide to try next image. placeholder
        // will remain in its place
        // if this leaves, iCurrentBitmap is not allocated
             
        // input buffers for image conversion
        TBrCtlImageCarrier& img = iImages->At( iImageIndex );
        iImageDataPtr.Set( (const TUint8*) img.RawData().Ptr(),
                                                img.RawData().Size() );
            
        
        TInt inputBufLen = iImageDataPtr.Size() + 1; // Input buffer length
        
        HBufC8* bufInput = HBufC8::NewL( inputBufLen + 1 );
        CleanupStack::PushL( bufInput );
        TPtr8 ptrInput( NULL,0,0 );
        ptrInput.Set( bufInput->Des() );
        ptrInput.Append( EView );
        ptrInput.Append( (const TUint8 *) iImageDataPtr.Ptr(), iImageDataPtr.Size() );
        
        // output buffer for image conversion
        if ( iDRMOutputBuf )
            {
            delete [] iDRMOutputBuf;
            iDRMOutputBuf = NULL;
            }
        TInt outputBufLen = iImageDataPtr.Size() + 256; // Output buffer length
        iDRMOutputBuf = new (ELeave) TUint8[outputBufLen];
        TPtr8 ptrOutput( iDRMOutputBuf, 0, outputBufLen );
        
        
        // Do we have a DRM image?
        TAgent agentDRM;
        TRequestStatus status;
        
        ContentAccess::CManager* manager = CManager::NewLC();

        RArray<ContentAccess::TAgent> agents;
       //Add agents to cleanup stack
		CleanupClosePushL(agents);
 
        manager->ListAgentsL( agents );
        for ( TInt i = 0; i < agents.Count(); i++ )
		    {
    		if ( agents[i].Name().Compare( KOmaDrm2AgentName ) == 0)
    			{
    			 agentDRM = agents[i];
    			 break;
    			}
    		}
    	
    	//Cleanup the agents
        CleanupStack::PopAndDestroy(/*agents*/);
	
    	// convert the DRM image (asynchronous)
        manager->AgentSpecificCommand(  agentDRM, 
                                        EBufferContainsOma1Dcf, 
									    iImageDataPtr,
									    ptrOutput, 
									    status );
        // wait for it to finish
        User::WaitForRequest(status);
        
        // Conversion completed ok (if not image is skipped)
        if ( status == KErrNone )
            {
            //Now decrypt the buffer.
		    error = manager->AgentSpecificCommand(   
		                                agentDRM,
		                                EDecryptOma1DcfBuffer,
										ptrInput,
									    ptrOutput);
            if ( !error )
                {                
                iImageDataPtr.Set( (const TUint8*) ptrOutput.Ptr(), 
                                                    ptrOutput.Size() );
                delete iConverter;
                iConverter = NULL;
                TRAP( error, iConverter = CMdaImageDescToBitmapUtility::NewL( *this ); );
                
                // Decrypted ok (if not image is skipped)
                if ( !error )
                    {
                    TRAP_IGNORE( iConverter->OpenL( iImageDataPtr ) );
                    }
                }
            }
        CleanupStack::PopAndDestroy(); // bufInput
        CleanupStack::Pop(); //manager        
        }
    }


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::MiuoConvertCompleteL( TInt aError )
//-----------------------------------------------------------------------------
//
void CBrowserViewImagesListBox::MiuoConvertCompleteL(TInt aError)
    {
    if ( !aError )
        {
        // create icon out of the converted bitmap
        // if retrying convert, we have original size bitmap so shrink it into thumbnail icon
        CGulIcon* icon = CreateIconL(iCurrentBitmap, iRetryingConvert);
        iCurrentBitmap = NULL;      // ownership transferred to icon
        iRetryingConvert = EFalse;  // no more retrying
        CleanupStack::PushL(icon);
        iIcons->AppendL(icon);
        CleanupStack::Pop();        // icon now owned by iIcons

        // append item
        TBuf<KMaxAltTextLength> buf;
        TInt cstart = 1;
        TInt cend = 1;
        buf = _L("");
        buf.AppendNum(iIcons->Count()-1);       // 0 is always the placeholder
        buf.Append(_L("\t"));

        TBrCtlImageCarrier& img = iImages->At(iImageIndex);

        if ( img.AltText().Length() > 0 )
            {
            buf.Append( img.AltText().Left( buf.MaxLength() - buf.Length() ) );
            }
        else
            {
            //get filename w/o extension from url
            cstart = img.Url().LocateReverse('/') + 1;
            cend   = img.Url().LocateReverse('.');
            if ( cend <= cstart ) cend = img.Url().Length();
                {
                buf.Append( img.Url().Mid
                    ( cstart,
                        ( cend - cstart ) < ( buf.MaxLength() - buf.Length() )
                            ?
                        ( cend - cstart )
                            :
                        ( buf.MaxLength() - buf.Length() )
                	    ) 
                    );
                }
            }
            
        // replace item (having placeholder icon) with real thumbnail
        TRAPD(err, iItemList->InsertL(iImageIndex,buf));
        // if succeeded, delete the old one that has moved next to the new item
        // in case error occurred, the placeholder will remain.
        if(err==KErrNone)
            iItemList->Delete(iImageIndex+1);

        // redraw list
        HandleItemAdditionL();

        // open next image and convert it
        ConvertNextImageL();
        }
    else
        {
        if( aError == KErrArgument )
            {
            // retry this image
            // iCurrentBitmap has been allocated when MiuoConvertComplete 
            // is called, so delete it
            DeleteCurrentBitmap();
            CreateCurrentBitmapL(ETrue);        // use original image size
            iRetryingConvert = ETrue;
            iConverter->ConvertL(*iCurrentBitmap);      // retry conversion
            }
        else
            {
            DeleteCurrentBitmap();
            // convert next image (anyway)
            ConvertNextImageL();
            }
        }
		}


//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::DeleteCurrentBitmap()
//-----------------------------------------------------------------------------
//
void CBrowserViewImagesListBox::DeleteCurrentBitmap()
    {
    delete iCurrentBitmap;
    iCurrentBitmap = NULL;
    }



//-----------------------------------------------------------------------------
//  CBrowserViewImagesListBox::DeleteCurrentBitmap()
//
// not used - comes from abstract base class
//-----------------------------------------------------------------------------
//
void CBrowserViewImagesListBox::MiuoCreateComplete(TInt /* aError */)
    {
    }


// End of File
