// EIKDCLBM.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <eikdclbm.h>
#include <eikfutil.h>
#include <eiklbx.pan>
#include <eikenv.h>
#include <barsread.h>
#include <eikon.rsg>

//
// class CDirContentsTextArray
//

CDirContentsTextArray::CDirContentsTextArray(const CDirContentsListBoxModel* aModel)
	: iModel(aModel)
	{
	TChar tmp(0);
	iParentIncMatchText.Fill(tmp);
	}

TInt CDirContentsTextArray::MdcaCount() const
	{
	return iModel->NumberOfItems();
	}

TPtrC CDirContentsTextArray::MdcaPoint(TInt aIndex) const
	{
	if (iModel->ItemIsParent(aIndex))
		return iParentIncMatchText;
	return iModel->ItemName(aIndex);
	}

//
// class TFileInfo
//

EXPORT_C CDirContentsListBoxModel::TFileInfo::TFileInfo()
	: iAtt(0), iSize(0)
	{}

//
// class CDirContentsListBoxModel
//

const KContentMask=0xc0;

EXPORT_C CDirContentsListBoxModel* CDirContentsListBoxModel::NewL(RFs& aFsSession,TUint aFlags)
	{ // static
	CDirContentsListBoxModel* self=new(ELeave) CDirContentsListBoxModel(aFsSession,aFlags);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop();
	return(self);
	}

CDirContentsListBoxModel::CDirContentsListBoxModel(RFs& aFsSession,TInt aFlags)
	: iFsSession(aFsSession), iFlags(aFlags|EAllowUid)
	{ }

EXPORT_C CDirContentsListBoxModel::~CDirContentsListBoxModel()
	{
	delete iCurrentPath;
	delete iExtension;
	delete iParentName;
	delete iDirList;
	delete iFileList;
	delete iItemTextArray;
	}

void CDirContentsListBoxModel::ConstructL()
	{
	iItemTextArray=new(ELeave) CDirContentsTextArray(this);
	}

EXPORT_C void CDirContentsListBoxModel::UpdateL()
	{
	delete iDirList;
	iDirList=NULL;
	delete iFileList;
	iFileList=NULL;
	TUint sortOrder=ESortByName;
	if (iFlags&EOrderByType)
		sortOrder=ESortNone;
	else if (iFlags&EOrderBySize)
		sortOrder=ESortBySize;
	else if (iFlags&EOrderByDate)
		sortOrder=ESortByDate;
	if (iFlags&ESortDescending)
		{
		if (sortOrder==ESortByName || sortOrder==ESortByUid)
			sortOrder|=EDescending;
		}
	else if (sortOrder==ESortBySize || sortOrder==ESortByDate)
		sortOrder|=EDescending;
//	const TUint includeUid=(iFlags&EAllowUid? KEntryAttAllowUid : 0);
	TInt attribs=KEntryAttNormal|KEntryAttSystem;
	if (iFlags&EShowHidden)
		attribs|=KEntryAttHidden;
	if (iFlags&EAllowUid)
		attribs|=KEntryAttAllowUid;
	if (iFlags&EShowDirsOnly)
		{
		CDir* fileList;
		const TInt ret=iFsSession.GetDir(*iCurrentPath,attribs|KEntryAttDir,ESortByName,fileList,iDirList);
//		const TInt ret=iFsSession.GetDir(*iCurrentPath,KEntryAttMatchExclusive|KEntryAttDir|includeUid,ESortByName,iDirList);
		CheckForErrorFromFileServerL(ret);
		if (ret==KErrNone)
			{
			delete fileList;
			if (iParse.IsRoot() && ~iFlags&EShowSystem)
				EikFileUtils::RemoveSystemDirectory(*iDirList);
		//		STATIC_CAST(CEikDir*,iDirList)->RemoveSystem();
			}
		}
	else if (iFlags&EShowFilesOnly)
		{
		const TInt ret=iFsSession.GetDir(*iCurrentPath,attribs,sortOrder,iFileList);
		CheckForErrorFromFileServerL(ret);
		}
	else
		{
		TInt ret=iFsSession.GetDir(*iCurrentPath,attribs,sortOrder,iFileList);
		if (ret)
			{
			CheckForErrorFromFileServerL(ret);
			return;
			}
		CDir* fileList;
		ret=iFsSession.GetDir(*iCurrentPath,attribs|KEntryAttDir,ESortByName,fileList,iDirList);
		if (ret)
			{
			delete iFileList;
			CheckForErrorFromFileServerL(ret);
			return;
			}
		delete fileList;
		if (iParse.IsRoot() && ~iFlags&EShowSystem)
			EikFileUtils::RemoveSystemDirectory(*iDirList);
	//		STATIC_CAST(CEikDir*,iDirList)->RemoveSystem();
		}
	if (sortOrder==ESortNone && iFileList)
		{
		TResourceReader reader;
		CEikonEnv::Static()->CreateResourceReaderLC(reader,R_EIK_ARRAY_FILE_SORT_TABLE);
		CEikFileSortTable* sortTable=new(ELeave) CEikFileSortTable;
		CleanupStack::PushL(sortTable);
		sortTable->ConstructFromResourceL(reader);
		TInt err=EikFileUtils::SortByTable(*iFileList,sortTable);
		CleanupStack::PopAndDestroy(2); // reader, sortTable
		if (err!=KErrNone)
			{
			delete iFileList;
			CheckForErrorFromFileServerL(err);
			}
		}
	}

EXPORT_C void CDirContentsListBoxModel::Reset()
	{
	delete iFileList;
	iFileList=NULL;
	delete iDirList;
	iDirList=NULL;
	delete iCurrentPath;
	iCurrentPath=NULL;
	iParse=TParse();
	}

void CDirContentsListBoxModel::CheckForErrorFromFileServerL(TInt aErrorCode)
	{
	if (aErrorCode)
		{
		iDirList=NULL;
		iFileList=NULL;
		iParse=TParse();
		if (aErrorCode!=KErrNotFound || (aErrorCode==KErrNotFound 
				&& !(iFlags & EShowSingleExt)))
			User::LeaveIfError(aErrorCode);
		}
	}

EXPORT_C void CDirContentsListBoxModel::SetSortOrder(CDirContentsListBoxModel::TSortOrder aSortOrder)
	{
	iFlags&=~ESortMask;
	iFlags|=aSortOrder;
	}

EXPORT_C CDirContentsListBoxModel::TSortOrder CDirContentsListBoxModel::SortOrder() const
	{
	const TUint order=iFlags&ESortMask;
	return STATIC_CAST(CDirContentsListBoxModel::TSortOrder,order);
	}

EXPORT_C void CDirContentsListBoxModel::SetAllowUid(TBool aAllow)
	{
	if (aAllow)
		iFlags|=EAllowUid;
	else
		iFlags&=~EAllowUid;
	}

EXPORT_C void CDirContentsListBoxModel::SetSortAscending(TBool aAscending)
	{
	if (aAscending)
		iFlags&=~ESortDescending;
	else
		iFlags|=ESortDescending;
	}

#pragma warning( disable : 4706 )

EXPORT_C void CDirContentsListBoxModel::SetCurrentPathL(const TDesC& aPath)
	{
	ChangeCurrentPathL(aPath);
	UpdateL();
	// determine parent name (set to NULL if no parent)
	delete iParentName;
	iParentName=NULL;
	if (ItemIsParent(0))
		{
		User::LeaveIfError(EikFileUtils::Parse(*iCurrentPath));
		TParsePtrC parse(*iCurrentPath);
		TBufC<KMaxFileName> buf=parse.Path();
		TFileName* name=new(ELeave) TFileName;
		CleanupStack::PushL(name);
		*name=buf.Des();
		TInt length=name->Length();
		TInt pos=--length;
		while (--pos)
			if (name->Mid(pos,1)==_L("\\"))
				break;
		name->Delete(length,1);
		name->Delete(0,pos+1);
		iParentName=name->AllocL();
		CleanupStack::PopAndDestroy(); // name
		}
	}

void CDirContentsListBoxModel::ChangeCurrentPathL(const TDesC& aPath)
	{
	User::LeaveIfError(EikFileUtils::Parse(aPath));
	TFileName* path=new(ELeave) TFileName;
	CleanupStack::PushL(path);
	*path=aPath;
	TParse parse;
	parse.Set(*path,NULL,NULL);
	if (!parse.NamePresent() && path->Length()<KMaxFileName)
		path->Append(_L("*"));
	if (iFlags&EShowSingleExt && !parse.ExtPresent())
		path->Append(*iExtension);
	delete iCurrentPath;
	iCurrentPath=NULL;
	iCurrentPath=path->AllocL();
	CleanupStack::PopAndDestroy();	// path
	iParse=parse;
	}

EXPORT_C void CDirContentsListBoxModel::SetExtensionL(const TDesC& aExt)
	{
	delete iExtension;
	iExtension=aExt.AllocL();
	iFlags|=EShowSingleExt|EShowFilesOnly;
	if (iCurrentPath)
		ChangeCurrentPathL(*iCurrentPath);
	}

EXPORT_C TInt CDirContentsListBoxModel::NumberOfItems() const
	{
	TInt numberOfItems=0;
	if (iDirList)
		numberOfItems+=iDirList->Count();
	if (iFileList)
		numberOfItems+=iFileList->Count();
	if ((iDirList || iFileList) && !iParse.IsRoot())
		++numberOfItems;
	return numberOfItems;
	}

EXPORT_C TEntry* CDirContentsListBoxModel::Item(TInt aItemIndex) const
	{
	__ASSERT_ALWAYS(aItemIndex>=0 && aItemIndex<NumberOfItems(),Panic(EEikPanicListBoxItemIsNull));
	if (ItemIsParent(0))
		{
		if (aItemIndex==0)
			return NULL;
		aItemIndex--;
		}
	if (iDirList && aItemIndex<iDirList->Count())
		return (TEntry*)&(*iDirList)[aItemIndex];
	else if (iFileList && iDirList)
		return (TEntry*)&(*iFileList)[aItemIndex-iDirList->Count()];
	else
		return (TEntry*)&(*iFileList)[aItemIndex];
	}

EXPORT_C TDesC& CDirContentsListBoxModel::ItemName(TInt aItemIndex) const
	{
	if (ItemIsParent(aItemIndex))
		return *iParentName;
	return Item(aItemIndex)->iName;
	}

EXPORT_C CDirContentsListBoxModel::TFileInfo CDirContentsListBoxModel::ItemInfo(TInt aItemIndex) const
	{
	TFileInfo info;
	if (ItemIsParent(aItemIndex))
		{
		TFileName path=*iCurrentPath;
		path.Delete(path.Length()-2,2);
		TEntry entry;
		if (iFsSession.Entry(path,entry)!=KErrNone)
			return info;
		info.iAtt=entry.iAtt;
		info.iSize=entry.iSize;
		info.iModified=entry.iModified;
		}
	else
		{
		const TEntry* entry=Item(aItemIndex);
		info.iAtt=entry->iAtt;
		info.iSize=entry->iSize;
		info.iModified=entry->iModified;
		}
	return info;
	}

EXPORT_C void CDirContentsListBoxModel::ChangeToParentDirL()
	{
	User::LeaveIfError(iParse.PopDir());
	SetCurrentPathL(iParse.FullName());
	}

EXPORT_C void CDirContentsListBoxModel::ChangeToSubDirL(TInt aItemIndex)
	{
	__ASSERT_DEBUG(ItemIsSubDir(aItemIndex), Panic(EEikPanicListBoxInvalidItemIndexSpecified));
	TFileName* name=new(ELeave) TFileName;
	CleanupStack::PushL(name);
	*name=ItemName(aItemIndex);
	User::LeaveIfError(iParse.AddDir(*name));
	CleanupStack::PopAndDestroy();   // name
	SetCurrentPathL(iParse.FullName());
	}

EXPORT_C TFileName CDirContentsListBoxModel::ItemFullName(TInt aItemIndex) const
	{
	if (!iCurrentPath)
		return _L("");
	TFileName path=*iCurrentPath;
	if (iFlags & EShowSingleExt)
		{
		const TInt extLength=iExtension->Length();
		path.Delete(path.Length()-extLength-1,extLength+1);
		}
	else
		path.Delete(path.Length()-1,1);
	if (!ItemIsParent(aItemIndex) && aItemIndex>=0)
		{
		path.Append(ItemName(aItemIndex));
		if (ItemIsSubDir(aItemIndex))
			path.Append(_L("\\"));
		}
	return path;
	}

EXPORT_C TBool CDirContentsListBoxModel::ItemIsParent(TInt aItemIndex) const
	{
	if (aItemIndex==0)
		return !iParse.IsRoot();
	return EFalse;
	}

EXPORT_C TBool CDirContentsListBoxModel::ItemIsSubDir(TInt aItemIndex) const
	{
	if (ItemIsParent(aItemIndex))
		return EFalse;
	const TEntry* entry=Item(aItemIndex);
	return entry->IsDir();
	}

EXPORT_C void CDirContentsListBoxModel::SetContent(TUint aContentFlags)
	{
	iFlags&=~KContentMask;
	iFlags|=aContentFlags;
	}
