// EIKDTLBM.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <eikdtlbm.h>
#include <eikfutil.h>

//
// class CDirectoryTreeListBoxModel
//

const TUint KContentMask=0x30;

EXPORT_C CDirectoryTreeListBoxModel::CDirectoryTreeListBoxModel(RFs& aFsSession,TInt aFlags)
	: iFsSession(aFsSession), iFlags(aFlags)
	{ }

EXPORT_C void CDirectoryTreeListBoxModel::CreateListForSpecifiedDriveL(TDriveNumber* aDrive)
	{
	if (!iHierListArray)
		iHierListArray=new(ELeave) CArrayFixSeg<CHierListItem*>(5);
	else
		RemoveAllItems();
	if (!aDrive)
		{
		CreateDriveListL();
		return;
		}
	CDir* fileList;
	CDir* dirList;
	const TInt val=(TInt)*aDrive - (TInt)EDriveA + 'A';
	TChar driveLetter(val);
	driveLetter.UpperCase();
	TBuf<1> drive;
	drive.Append(driveLetter);
	TBuf<4> root;
	CHierListItem* rootItem;
	rootItem=new(ELeave) CHierListItem((TInt16)CHierListItem::EExpanded);
	rootItem->SetTextL(drive);
	AddItemL(rootItem,-1,-1);
	root.Append(drive);
	root.Append(_L(":\\*"));
	TInt attribs=KEntryAttDir|KEntryAttSystem;
	if (iFlags&EShowHidden)
		attribs|=KEntryAttHidden;
	User::LeaveIfError(iFsSession.GetDir(root,attribs,ESortByName,fileList,dirList));
	delete fileList;
	if (~iFlags&EShowSystem)
		EikFileUtils::RemoveSystemDirectory(*dirList);
//		STATIC_CAST(CEikDir*,dirList)->RemoveSystem();
	CleanupStack::PushL(dirList);
	TInt itemIndex=0;
	const TInt count=dirList->Count();
	for (TInt ii=0;ii<count;ii++)
		{
		const TEntry& entry=(*dirList)[ii];
		CHierListItem* item;
		item=new(ELeave) CHierListItem((TInt16)0);
		item->SetTextL(entry.iName);
		AddItemL(item,0,itemIndex++);
		}
	CleanupStack::PopAndDestroy();
	}

void CDirectoryTreeListBoxModel::CreateDriveListL()
	{
	TDriveList driveList;
	User::LeaveIfError(iFsSession.DriveList(driveList));
	for (TInt ii=0;ii<KMaxDrives;ii++)
		if (driveList[ii])
			{
			TChar drive(ii+'A');
			drive.UpperCase();
			TBuf<1> buf;
			buf.Append(drive);
			CHierListItem* item;
			item=new(ELeave) CHierListItem((TInt16)0);
			item->SetTextL(buf);
			AddItemL(item,-1,-1);
			}
	}

EXPORT_C void CDirectoryTreeListBoxModel::ExpandItemL(TInt aItemToBeExpanded)
	{
	const TInt index=aItemToBeExpanded;
	CHierListItem* itemToBeExpanded=Item(index);
	if (itemToBeExpanded->IsExpanded())
		return;
	TFileName path=FullPath(index);
	if (path.Length()<KMaxFileName)
		path.Append(_L("*"));
	CDir* dirList;
	CDir* fileList;
	TInt attribs=KEntryAttDir|KEntryAttSystem;
	if (iFlags&EShowHidden)
		attribs|=KEntryAttHidden;
	User::LeaveIfError(iFsSession.GetDir(path,attribs,ESortByName,fileList,dirList));
	delete fileList;
	CleanupStack::PushL(dirList);
	if (itemToBeExpanded->Level()==0 && ~iFlags&EShowSystem)
		EikFileUtils::RemoveSystemDirectory(*dirList);
//		STATIC_CAST(CEikDir*,dirList)->RemoveSystem();
	TInt newItemIndex=index;
	const TInt newEntryCount=dirList->Count();
	for (TInt ii=0;ii<newEntryCount;ii++)
		{
		const TEntry& entry=(*dirList)[ii];
		CHierListItem* newItem;
		newItem=new(ELeave) CHierListItem((TInt16)0);
		newItem->SetTextL(entry.iName);
		AddItemL(newItem,index,newItemIndex++);
		}
	CleanupStack::PopAndDestroy();
	itemToBeExpanded->SetExpanded();
	}

EXPORT_C TFileName CDirectoryTreeListBoxModel::FullPath(TInt aItemIndex) const
	{
	if (aItemIndex==-1)
		return _L("");
	TFileName path=ItemText(aItemIndex);
	TInt level=Item(aItemIndex)->Level();
	TInt count=0;
	while (level)
		{
		count++;
		if (Item(aItemIndex-count)->Level()==level-1)
			{
			path.Insert(0,_L("\\"));
			path.Insert(0,ItemText(aItemIndex-count));
			if (--level==0)
				break;
			}
		}
	path.Insert(1,_L(":"));
	path.Append(_L("\\"));
	return path;
	}

TInt CDirectoryTreeListBoxModel::PathExists(const TDesC& aPath) const
	{
	RDir dir;
	const TInt ret=dir.Open(iFsSession,aPath,EFileRead|EFileShareAny);
	if (!ret)
		dir.Close();
	return ret;
	}

EXPORT_C void CDirectoryTreeListBoxModel::UpdateL()
// will this work for lists containing more than one drive ???
	{
	TInt count=NumberOfItems();
	TInt ii=-1;
	while (++ii<count)
		{
		TFileName path=FullPath(ii);
		if (path.Length()<KMaxFileName)
			path.Append(_L("*"));
		const TInt err=PathExists(path);
		if (err==KErrPathNotFound || err==KErrNotReady)
			{
			RemoveItem(ii--);
			count=NumberOfItems();
			if (!count) // disk must have been removed
				User::LeaveIfError(err);
			}
		else
			User::LeaveIfError(err);
		}
	ii=-1;
	while (++ii<count)
		{
		TFileName path=FullPath(ii);
		if (path.Length()==KMaxFileName)
			continue;
		path.Append(_L("*"));
		CDir* dirList;
		CDir* fileList;
		TInt attribs=KEntryAttDir|KEntryAttSystem;
		if (iFlags&EShowHidden)
			attribs|=KEntryAttHidden;
		User::LeaveIfError(iFsSession.GetDir(path,attribs,ESortByName,fileList,dirList));
		delete fileList;
		CHierListItem* item=Item(ii);
		if (item->Level()==0 && ~iFlags&EShowSystem)
			EikFileUtils::RemoveSystemDirectory(*dirList);
		if (!item->IsExpanded())
			delete dirList;
		else
			{
			CleanupStack::PushL(dirList);
			const TInt dirCount=dirList->Count();
			TInt inc=1;
			for (TInt jj=0;jj<dirCount;jj++)
				{
				const TEntry& entry=(*dirList)[jj];
				TParse parse;
				User::LeaveIfError(parse.Set(path,NULL,NULL));
				TInt level=1;
				while (!parse.PopDir())
					level++;
				TInt index=ii+jj+inc;
				CHierListItem* old=Item(index);
				while (old && old->Level()>level)
					{
					old=Item(++index);
					++inc;
					}
				if (old==NULL || entry.iName!=*(old->Text()))
					{
					CHierListItem* item=new(ELeave) CHierListItem((TInt16)0);
					item->SetTextL(entry.iName);
//					TInt index=ii+jj;
//					const TInt next=NextSiblingIndex(index);
//					if (next!=KErrNotFound)
//						index+=(next-index);
					AddItemL(item,ii,index-1);
					}
				}
			count=NumberOfItems();
			CleanupStack::PopAndDestroy(); // dirList
			}
		}
	}

EXPORT_C void CDirectoryTreeListBoxModel::SetContent(TInt aContentFlags)
	{
	iFlags&=~KContentMask;
	iFlags|=aContentFlags;
	}
