// APGICNFL.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <s32file.h>
#include "apgstd.h"
#include "ApgIcnfl.h"

//
// Class CApaMaskedBitmap
//

CApaMaskedBitmap::CApaMaskedBitmap()
:CFbsBitmap()
	{}

EXPORT_C CApaMaskedBitmap::~CApaMaskedBitmap()
	{
	delete iMask;
	}

EXPORT_C CApaMaskedBitmap* CApaMaskedBitmap::NewLC()
	{
	CApaMaskedBitmap* self=new(ELeave) CApaMaskedBitmap;
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

EXPORT_C CApaMaskedBitmap* CApaMaskedBitmap::NewL(CApaMaskedBitmap* aSourceIcon)
	{
	CApaMaskedBitmap* self=new(ELeave) CApaMaskedBitmap;
	CleanupStack::PushL(self);
	self->ConstructL();
	User::LeaveIfError( self->iMask->Duplicate(aSourceIcon->Mask()->Handle()) );
	User::LeaveIfError( self->Duplicate(aSourceIcon->Handle()) );
	CleanupStack::Pop();	// self
	return self;
	}

void CApaMaskedBitmap::ConstructL()
	{
	__DECLARE_NAME(_S("CApaMaskedBitmap"));
	if (!iFbs) 
		User::Leave(KErrCouldNotConnect);
	iMask=new(ELeave) CFbsBitmap;
	}

EXPORT_C CFbsBitmap* CApaMaskedBitmap::Mask() const
	{
	return iMask;
	}

EXPORT_C void CApaMaskedBitmap::InternalizeL(RReadStream& aStream)
	{
	CFbsBitmap::InternalizeL(aStream);
	aStream >> *iMask;
	}

EXPORT_C void CApaMaskedBitmap::ExternalizeL(RWriteStream& aStream) const
	{
	CFbsBitmap::ExternalizeL(aStream);
	aStream << *iMask;
	}

//
// Class CApaAppInfoFile
//

CApaAppInfoFile::CApaAppInfoFile()
	{}

void CApaAppInfoFile::TCaptionHeader::InternalizeL(RReadStream& aStream)
	{
	aStream >> iCaption;
	iLanguage=(TLanguage)aStream.ReadInt16L();
	}

void CApaAppInfoFile::TCaptionHeader::ExternalizeL(RWriteStream& aStream) const
	{
	aStream	<< iCaption;
	aStream.WriteInt16L(iLanguage);
	}

void CApaAppInfoFile::TIconHeader::InternalizeL(RReadStream& aStream)
	{
	aStream >> iIcon;
	iIconSideInPixels=aStream.ReadInt16L();
	}

void CApaAppInfoFile::TIconHeader::ExternalizeL(RWriteStream& aStream) const
	{
	aStream	<< iIcon;
	aStream.WriteInt16L(iIconSideInPixels);
	}

void CApaAppInfoFile::TDataTypeHeader::InternalizeL(RReadStream& aStream)
	{
	aStream >> iDataType;
	iPriority=aStream.ReadInt16L();
	}

void CApaAppInfoFile::TDataTypeHeader::ExternalizeL(RWriteStream& aStream) const
	{
	aStream << iDataType;
	aStream.WriteInt16L(iPriority);
	}

CApaAppInfoFile::~CApaAppInfoFile()
	{
	delete iCaptionHeaderArray;
	delete iIconHeaderArray;
	delete iDataTypeHeaderArray;
	delete iStore;
	iFs.Close();
	}

void CApaAppInfoFile::ConstructL()
	{
	User::LeaveIfError(iFs.Connect());
	iCaptionHeaderArray=new(ELeave) CArrayFixFlat<TCaptionHeader>(4);
	iIconHeaderArray=new(ELeave) CArrayFixFlat<TIconHeader>(4);
	iDataTypeHeaderArray=new(ELeave) CArrayFixFlat<TDataTypeHeader>(4);
	}

//
// Class CApaAppInfoFileReader
//

CApaAppInfoFileReader::CApaAppInfoFileReader()
	{}

EXPORT_C CApaAppInfoFileReader::~CApaAppInfoFileReader()
	{
	delete iDefaultCaption;
	}

EXPORT_C CApaAppInfoFileReader* CApaAppInfoFileReader::NewLC(const TDesC& aFileName,TUid aUid)
	{
	CApaAppInfoFileReader* self=new(ELeave) CApaAppInfoFileReader;
	CleanupStack::PushL(self);
	self->ConstructL(aFileName,aUid);
	return self;
	}

EXPORT_C CApaAppInfoFileReader* CApaAppInfoFileReader::NewL(const TDesC& aFileName,TUid aUid)
	{
	CApaAppInfoFileReader* self=CApaAppInfoFileReader::NewLC(aFileName,aUid);
	CleanupStack::Pop(); // self
	return self;
	}

void CApaAppInfoFileReader::ConstructL(const TDesC& aFileName,TUid aMostDerivedUid)
	{
	__DECLARE_NAME(_S("CApaAppInfoFileReader"));
	CApaAppInfoFile::ConstructL();
	TParse parse;
	User::LeaveIfError(parse.Set(aFileName,NULL,NULL));
	iDefaultCaption=parse.Name().AllocL();
	CFileStore* store = CFileStore::OpenL(iFs,aFileName,EFileRead|EFileShareReadersOnly);
	iStore = store;
	const TUidType& type=store->Type();
	if (type[1]!=KUidAppInfoFile || (aMostDerivedUid!=KNullUid && type[2]!=aMostDerivedUid))
		// it's the wrong file!!!!!
		User::Leave(KErrCorrupt);
	RStoreReadStream inStream;
	inStream.OpenLC(*store,store->Root());
	InternalizeL(inStream);
	CleanupStack::PopAndDestroy();			// inStream
	}

void CApaAppInfoFileReader::InternalizeL(RReadStream& aStream)
	{
	aStream>> *iCaptionHeaderArray;		// Internalizes the headers only
	aStream>> *iIconHeaderArray;
	aStream>> iCapability;
	TInt version=EAifVersionOriginal;
	TRAPD(err,version=aStream.ReadInt32L());
	if (version<EAifVersionAddsDataType)
		return;
	aStream>> *iDataTypeHeaderArray;
	}

EXPORT_C TApaAppCaption CApaAppInfoFileReader::CaptionL(TLanguage aLanguage)
// Find language id and return matching caption, loaded from file.
// Does not allocate storage for the caption so there's no need to delete the array elements.
	{
	const TInt count=iCaptionHeaderArray->Count();
	for (TInt i=0;i<count;i++)
		{
		TCaptionHeader* pCaptionHeader=(&(*iCaptionHeaderArray)[i]);
		if (pCaptionHeader->iLanguage==aLanguage)
			{
			TApaAppCaption caption;
			RStoreReadStream inStream;
			inStream.OpenLC(*iStore,pCaptionHeader->iCaption.AsId());
			inStream >> caption;
			CleanupStack::PopAndDestroy();			// inStream
			return caption;
			}
		}
	return *iDefaultCaption;
	}

EXPORT_C void CApaAppInfoFileReader::StretchDrawL(CFbsBitmap* aSource,CFbsBitmap* aTarget,TSize aSizeInPixels)
//
	{
	User::LeaveIfError(aTarget->Create(aSizeInPixels,EGray4));
	CFbsBitmapDevice* bitDev=CFbsBitmapDevice::NewL(aTarget);
	CleanupStack::PushL(bitDev);
	CFbsBitGc* gc;
	User::LeaveIfError(bitDev->CreateContext((CGraphicsContext*&)gc));
	gc->DrawBitmap(TRect(aSizeInPixels),aSource);
	delete gc;
	CleanupStack::PopAndDestroy();	// bitDev
	}

EXPORT_C CApaMaskedBitmap* CApaAppInfoFileReader::CreateMaskedBitmapL(TInt aIconSideInPixels)
// Find nearest size that isn't too big and return that (no stretching anymore)
// Returned bitmap is not owned here, caller must delete it.
// If there are no bitmaps in the file this method leaves with KErrNotFound
//
	{
	const TInt count=iIconHeaderArray->Count();
	if (count==0)
		User::Leave(KErrNotFound);
	//
	TInt closest=0;
	TInt smallest=0;
	TInt minSoFar=KMaxTInt;
	TInt smallestSoFar=KMaxTInt;
	TInt delta=0;
	for (TInt i=0;i<count;i++)
		{
		TIconHeader* pIconHeader=(&(*iIconHeaderArray)[i]);
		delta = aIconSideInPixels-pIconHeader->iIconSideInPixels; // Abs()
		if (pIconHeader->iIconSideInPixels<smallestSoFar)
			{ // the smallest is used if they're all too big
			smallest = i;
			smallestSoFar = pIconHeader->iIconSideInPixels;
			}
		if (delta>=0 && delta<minSoFar)
			{
			minSoFar=delta;
			closest=i;
			if (delta==0)
				break;
			}
		}
	//
	if (minSoFar==KMaxTInt)
		closest = smallest;
	//
	CApaMaskedBitmap* icon=CApaMaskedBitmap::NewLC();
	RStoreReadStream inStream;
	inStream.OpenLC(*iStore,(*iIconHeaderArray)[closest].iIcon.AsId());
	inStream >> *icon;
	CleanupStack::PopAndDestroy();			// inStream
	CleanupStack::Pop();					// icon
	//
	if (minSoFar==KMaxTInt)
		{// all the icons are too big - squash down the smallest
		CApaMaskedBitmap* newIcon=CApaMaskedBitmap::NewLC();
		TSize iconSize(aIconSideInPixels,aIconSideInPixels);
		StretchDrawL(icon,newIcon,iconSize);
		StretchDrawL(icon->Mask(),newIcon->Mask(),iconSize);
		CleanupStack::Pop();				// newIcon
		delete icon;
		return newIcon;
		}
	return icon;
	}


EXPORT_C void CApaAppInfoFileReader::Capability(TDes8& aInfo)const
	{
	TApaAppCapabilityBuf buf(iCapability);
	TApaAppCapability::CopyCapability(aInfo,buf);
	}

EXPORT_C void CApaAppInfoFileReader::DataTypesSupportedL(CArrayFix<TDataTypeWithPriority>& aTypeList) const
	{
	__ASSERT_DEBUG(aTypeList.Count()==0,Panic(EDPanicArrayNotEmpty));
	__ASSERT_DEBUG(iDataTypeHeaderArray,User::Invariant());
	TInt count=iDataTypeHeaderArray->Count();
	for (TInt i=0; i<count; i++)
		{
		TDataTypeHeader& header=(*iDataTypeHeaderArray)[i];
		RStoreReadStream inStream;
		inStream.OpenLC(*iStore,header.iDataType.AsId());
		TDataType dataType;
		inStream >> dataType;
		aTypeList.AppendL(TDataTypeWithPriority(dataType,header.iPriority));
		CleanupStack::PopAndDestroy(); // inStream
		}
	}

//
// Class CApaAppInfoFileWriter
//

CApaAppInfoFileWriter::CApaAppInfoFileWriter()
	{}

EXPORT_C CApaAppInfoFileWriter::~CApaAppInfoFileWriter()
// Must delete caption and icon pointers that have been set in AddCaptionL and AddIconL
	{
	const TInt captionCount=iCaptionHeaderArray->Count();
	for (TInt i=0;i<captionCount;i++)
		{
		const TCaptionHeader& pCaption=(*iCaptionHeaderArray)[i];
		if (pCaption.iCaption.IsPtr())
			delete pCaption.iCaption.AsPtr();
		}
	const TInt iconCount=iIconHeaderArray->Count();
	for (TInt j=0;j<iconCount;j++)
		{
		const TIconHeader& pIcon=(*iIconHeaderArray)[j];
		if (pIcon.iIcon.IsPtr())
			delete pIcon.iIcon.AsPtr();
		}
	const TInt dataCount=iDataTypeHeaderArray->Count();
	for (TInt k=0;k<dataCount;k++)
		{
		const TDataTypeHeader& pData=(*iDataTypeHeaderArray)[k];
		if (pData.iDataType.IsPtr())
			delete pData.iDataType.AsPtr();
		}
	delete iMap;		// Must delete before iStore
	}

EXPORT_C CApaAppInfoFileWriter* CApaAppInfoFileWriter::NewLC(const TDesC& aFileName,TUid aUid)
	{
	CApaAppInfoFileWriter* self=new(ELeave) CApaAppInfoFileWriter;
	CleanupStack::PushL(self);
	self->ConstructL(aFileName,aUid);
	return self;
	}

void CApaAppInfoFileWriter::ConstructL(const TDesC& aFileName,TUid aUid)
	{
	__DECLARE_NAME(_S("CApaAppInfoFileWriter"));
	CApaAppInfoFile::ConstructL();
	TInt ret=iFs.MkDirAll(aFileName);
    if (ret!=KErrAlreadyExists)
        User::LeaveIfError(ret);
	CFileStore* store=CDirectFileStore::ReplaceL(iFs,aFileName,EFileRead|EFileWrite);
	iStore = store;
	store->SetTypeL(TUidType(KDirectFileStoreLayoutUid,KUidAppInfoFile,aUid));
	iMap=CStoreMap::NewL(*store);	// Ready for Storing components
	}

void CApaAppInfoFileWriter::ExternalizeL(RWriteStream& aStream) const
	{
	aStream<< *iCaptionHeaderArray;
	aStream<< *iIconHeaderArray;
	aStream<< iCapability;
	aStream.WriteInt32L(EAifVersionAddsDataType);
	aStream<< *iDataTypeHeaderArray;
	}

EXPORT_C void CApaAppInfoFileWriter::StoreL()
	{
	RStoreWriteStream outStream(*iMap);
	TStreamId id=outStream.CreateLC(*iStore);
	ExternalizeL(outStream);
	outStream.CommitL();
	CleanupStack::PopAndDestroy();		// outStream
	iMap->Reset();
	iStore->SetRootL(id);
	iStore->CommitL();
	}

EXPORT_C void CApaAppInfoFileWriter::AddCaptionL(TLanguage aLanguage,const TDesC& aCaption)
// Write caption out to a new stream and add to iCaptionHeaderArray
	{
	if (aCaption.Length()>KApaMaxAppCaption)
		User::Leave(KErrBadName);
	TCaptionHeader captionHeader;
	captionHeader.iLanguage=aLanguage;
	captionHeader.iCaption=aCaption.AllocL();
	CleanupStack::PushL(captionHeader.iCaption.AsPtr());
	RStoreWriteStream outStream;
	TStreamId id=outStream.CreateLC(*iStore);
	outStream << *captionHeader.iCaption;
	outStream.CommitL();
	CleanupStack::PopAndDestroy();				// outStream
	iMap->BindL(captionHeader.iCaption,id);
	iCaptionHeaderArray->AppendL(captionHeader);
	CleanupStack::Pop();						// iCaption
	}
	
EXPORT_C void CApaAppInfoFileWriter::AddIconL(const TDesC& aIconFileName)
// Icon file must contain 2 bitmaps: icon and mask, and they are assumed to be the same size.
	{
	CApaMaskedBitmap* icon=CApaMaskedBitmap::NewLC();
	User::LeaveIfError(icon->Load(aIconFileName,0));
	User::LeaveIfError((icon->Mask())->Load(aIconFileName,1));
	CleanupStack::Pop();						// icon
	AddIconL(*icon);
	}

EXPORT_C void CApaAppInfoFileWriter::AddIconL(CApaMaskedBitmap& aIcon)
// Guaranteed to take ownership of the aIcon
// Will delete aIcon if it leaves
	{
	CleanupStack::PushL(&aIcon);
	TIconHeader iconHeader;
	iconHeader.iIcon = &aIcon;
	iconHeader.iIconSideInPixels = aIcon.SizeInPixels().iWidth;
	RStoreWriteStream outStream;
	TStreamId id=outStream.CreateLC(*iStore);
	outStream << *iconHeader.iIcon;
	outStream.CommitL();
	CleanupStack::PopAndDestroy();				// outStream
	iMap->BindL(iconHeader.iIcon,id);
	iIconHeaderArray->AppendL(iconHeader);
	CleanupStack::Pop();						// aIcon
	}


EXPORT_C TInt CApaAppInfoFileWriter::SetCapability(const TDesC8& aInfo)
	{
	// check that aInfo is of a permissable length
	TApaAppCapabilityBuf buf;
	TApaAppCapability::CopyCapability(buf,aInfo);
	iCapability = buf();
	return KErrNone;
	}

EXPORT_C void CApaAppInfoFileWriter::AddDataTypeL(const TDataTypeWithPriority& aTypePriority)
	{
	__ASSERT_DEBUG(aTypePriority.iDataType.Des8().Length()>0,Panic(EDPanicBadDataType));
	__ASSERT_DEBUG(aTypePriority.iPriority<KDataTypePriorityUserSpecified,Panic(EDPanicBadDataType));
	TDataTypeHeader header;
	TDataType* dataType=new(ELeave) TDataType(aTypePriority.iDataType);
	CleanupStack::PushL(dataType);
	header.iDataType=dataType;
	RStoreWriteStream outStream;
	TStreamId id=outStream.CreateLC(*iStore);
	outStream << *header.iDataType;
	outStream.CommitL();
	CleanupStack::PopAndDestroy();
	iMap->BindL(header.iDataType,id);
	header.iPriority=aTypePriority.iPriority;
	iDataTypeHeaderArray->AppendL(header);
	CleanupStack::Pop(); // header.iDataType
	}
