// TLBOX2.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <basched.h>
#include <badesca.h>
#include <coecntrl.h>
#include <eikenv.h>
#include <eikappui.h>
#include <eikhlbx.h>
#include <eikhlbm.h>
#include <eikhlbi.h>
#include <eikdtlbx.h>
#include <eikdtlbm.h>
#include <eikdclbx.h>
#include <eiklbx.hrh>
#include <eikcmds.hrh>
#include <eikapp.h>
#include <eikdoc.h>
#include <eikon.mbg>
#include <tlbox2.rsg>
#include "tlbox2.hrh"

const TInt16 KFolderOpenBitmapIndex = 0;
const TInt16 KFolderClosedBitmapIndex = 1;

class CTestHierarchicalListBoxModel : public CHierarchicalListBoxModel
	{
public:	
	CTestHierarchicalListBoxModel(RFs& aFsSession);
	~CTestHierarchicalListBoxModel();
	void CreateRootListL();
public: // framework
	void ExpandItemL(TInt aItemIndex);
private:
	void SearchForNonSpaceChar(TInt& aCharCount,TInt& aLength,TInt& aStartPos,TDes& aFilePortion,TDes& aBuf) const;
	void SearchForFullTextString(TInt& aCharCount,TInt& aLength,TInt& aStartPos,
									TDes& aFilePortion,TDes& aText) const;
	void CreateItemL(TDes* aText,TInt aParentIndex,TInt aIndexOfSiblingToInsetAfter);
	TPtrC CharFromBuffer(TInt aCharPos,const TDesC& aBuffer) const;
private:
	RFs iFsSession;
	RFile iFile;
	};

class CTestHierarchicalListBox : public CEikHierarchicalListBox
	{
public:
	void ConstructL(const CCoeControl* aParent,TInt aListBoxFlags=0);
	CTestHierarchicalListBoxModel* ThlModel() const { return (CTestHierarchicalListBoxModel*)iModel; }
	};

class CTestHierarchicalListItemDrawer : public CHierarchicalListItemDrawer
	{
public:
	CTestHierarchicalListItemDrawer(CTestHierarchicalListBoxModel* aModel,const CFont* aFont,CArrayPtrFlat<CFbsBitmap>* aBitmaps);
protected: // from CHierarchicalListItemDrawer
	CFbsBitmap* ItemBitmap(TInt aItemIndex) const;
	};

//
// class CTestHierarchicalListBox
//

void CTestHierarchicalListBox::ConstructL(const CCoeControl* aParent,TInt aListBoxFlags)
	{
	iModel=new(ELeave) CTestHierarchicalListBoxModel(iEikonEnv->FsSession());
	TPtrC system;
	CFbsBitmap* bitmap=iEikonEnv->CreateBitmapL(system,EMbmEikonFileopen);
	CArrayPtrFlat<CFbsBitmap>* bitmaps=new(ELeave) CArrayPtrFlat<CFbsBitmap>(2);
	CleanupStack::PushL(bitmaps);
	bitmaps->AppendL(bitmap);
	bitmap=iEikonEnv->CreateBitmapL(system,EMbmEikonFileclsd);
	bitmaps->AppendL(bitmap);
	CleanupStack::Pop();
	iItemDrawer=new(ELeave) CTestHierarchicalListItemDrawer((CTestHierarchicalListBoxModel*)iModel,iEikonEnv->NormalFont(),bitmaps);
	ThlModel()->CreateRootListL();
	CEikListBox::ConstructL(aParent,aListBoxFlags);
	}

//
// class CTestHierarchicalListItemDrawer
//

CTestHierarchicalListItemDrawer::CTestHierarchicalListItemDrawer(CTestHierarchicalListBoxModel* aModel,
																  const CFont* aFont,
																  CArrayPtrFlat<CFbsBitmap>* aBitmaps)
	: CHierarchicalListItemDrawer(aModel,aFont,aBitmaps)
	{}

CFbsBitmap* CTestHierarchicalListItemDrawer::ItemBitmap(TInt aItemIndex) const
	{
	if (!iBitmaps || aItemIndex<=-1 || aItemIndex>=iModel->NumberOfItems())
		return NULL;
	TInt bitmapIndex;
	if (iModel->Item(aItemIndex)->IsExpanded())
		bitmapIndex=KFolderOpenBitmapIndex;
	else
		bitmapIndex=KFolderClosedBitmapIndex;
	if (bitmapIndex==-1)
		return NULL;
	return (*iBitmaps)[bitmapIndex];
	}

//
// class CTestHierarchicalListBoxModel
//

CTestHierarchicalListBoxModel::CTestHierarchicalListBoxModel(RFs& aFsSession)
	: iFsSession(aFsSession)
	{
	}

CTestHierarchicalListBoxModel::~CTestHierarchicalListBoxModel()
	{
	iFile.Close();
	}

void CTestHierarchicalListBoxModel::CreateRootListL()
	{
	iHierListArray=new(ELeave) CArrayFixSeg<CHierListItem*>(5);
	TPtrC filePath;
	filePath.Set(_L("z:\\system\\test\\tlbox2.txt"));
	User::LeaveIfError(iFile.Open(iFsSession,filePath,EFileRead|EFileShareReadersOnly));
	TInt startPos=0;
	TBuf<64> filePortion;
#if defined(_UNICODE)
	TBuf8<64> narrowBufferToReadFile;
	User::LeaveIfError(iFile.Read(startPos,narrowBufferToReadFile));
	filePortion.Copy(narrowBufferToReadFile);
#else
	User::LeaveIfError(iFile.Read(startPos,filePortion));
#endif
	TInt ii=-1;
	TInt length=filePortion.Length();
	while (length==64)
		{
		TBuf<16> text;
		if (ii==length)
			{
			startPos+=length;
#if defined(_UNICODE)
			User::LeaveIfError(iFile.Read(startPos,narrowBufferToReadFile));
			filePortion.Copy(narrowBufferToReadFile);
#else
			User::LeaveIfError(iFile.Read(startPos,filePortion));
#endif
			ii=-1;
			length=filePortion.Length();
			}
		while (++ii<length)
			{
			TBuf<1> buf=CharFromBuffer(ii,filePortion);
			TChar tmp(buf[0]);
			if (tmp=='0')
				{
				SearchForNonSpaceChar(ii,length,startPos,filePortion,buf);
				text.Zero();
				text.Append(buf);
				SearchForFullTextString(ii,length,startPos,filePortion,text);
				CreateItemL(&text,-1,-1);
				}
			}
		}
	}

void CTestHierarchicalListBoxModel::ExpandItemL(TInt aItemIndex)
	{
	CHierListItem* itemToBeExpanded=Item(aItemIndex);
	if (itemToBeExpanded->IsExpanded())
		return;
	CDesCArray* items=new(ELeave) CDesCArrayFlat(3);
	CleanupStack::PushL(items);

	TPtrC itemName(ItemText(aItemIndex));

	items->AppendL(itemName);
	
	TInt parentIndex=ParentIndex(aItemIndex);
	while (parentIndex!=-1)
		{
		items->InsertL(0,ItemText(parentIndex));
		parentIndex=ParentIndex(parentIndex);
		}
	TBuf<64> filePortion;
	TInt startPos=0;
#if defined(_UNICODE)
	TBuf8<64> narrowBufferToReadFile;
	User::LeaveIfError(iFile.Read(startPos,narrowBufferToReadFile));
	filePortion.Copy(narrowBufferToReadFile);
#else
	User::LeaveIfError(iFile.Read(startPos,filePortion));
#endif
	TInt searchLevel=0;
	TInt length=filePortion.Length();
	TBool pathNotFound=ETrue;
	TInt ii=-1;
	while (pathNotFound)
		{
		if (ii==length)
			{
			startPos+=length;
#if defined(_UNICODE)
			User::LeaveIfError(iFile.Read(startPos,narrowBufferToReadFile));
			filePortion.Copy(narrowBufferToReadFile);
#else
			User::LeaveIfError(iFile.Read(startPos,filePortion));
#endif
			ii=-1;
			length=filePortion.Length();
			}
		while (++ii<length)
			{
			TBuf<1> buf=CharFromBuffer(ii,filePortion);
			TChar tmp(buf[0]);
			if ((tmp>='A' && tmp <='Z') || (tmp>='a' && tmp <='z'))
				{
				TBuf<16> text;
				text.Append(buf);
				SearchForFullTextString(ii,length,startPos,filePortion,text);
				if (text==(*items)[searchLevel])
					{
					searchLevel++;
					if (searchLevel==items->Count())
						{
						pathNotFound=EFalse;
						break;
						}
					}
				}
			}
		}
	CleanupStack::PopAndDestroy();
	TInt parentLevel=itemToBeExpanded->Level();
	TChar targetLevel(parentLevel+'0'+1);
	TInt newItemIndex=aItemIndex;
	TBool foundAllChildren=EFalse;
	while (!foundAllChildren)
		{
		if (ii==length)
			{
			if (length<64)
				foundAllChildren=ETrue;
			else
				{
				startPos+=length;
#if defined(_UNICODE)
				User::LeaveIfError(iFile.Read(startPos,narrowBufferToReadFile));
				filePortion.Copy(narrowBufferToReadFile);
#else
				User::LeaveIfError(iFile.Read(startPos,filePortion));
#endif
				ii=-1;
				length=filePortion.Length();
				}
			}
		while (++ii<length)
			{
			TBuf<1> buf=CharFromBuffer(ii,filePortion);
			TChar tmp(buf[0]);
			if (tmp==targetLevel)
				{
				TBuf<16> text;
				SearchForNonSpaceChar(ii,length,startPos,filePortion,buf);
				text.Append(buf);
				SearchForFullTextString(ii,length,startPos,filePortion,text);
				CreateItemL(&text,aItemIndex,newItemIndex++);
				}
			else if ((tmp>='0' && tmp <='9') && tmp<targetLevel)
				{
				foundAllChildren=ETrue;
				break;
				}
			}
		}
	itemToBeExpanded->SetExpanded();
	}

void CTestHierarchicalListBoxModel::SearchForNonSpaceChar(TInt& aCharCount,TInt& aLength,TInt& aStartPos,
														  TDes& aFilePortion,TDes& aBuf) const
	{
	while (++aCharCount<aLength)
		{
		aBuf=CharFromBuffer(aCharCount,aFilePortion);
		TChar tmp(aBuf[0]);
		if (tmp!=' ')
			break;
		}
	if (aCharCount==aLength)
		{
		aStartPos+=aLength;
#if defined(_UNICODE)
		TBuf8<64> narrowBufferToReadFile;
		User::LeaveIfError(iFile.Read(aStartPos,narrowBufferToReadFile));
		aFilePortion.Copy(narrowBufferToReadFile);
#else
		User::LeaveIfError(iFile.Read(aStartPos,aFilePortion));
#endif
		aCharCount=-1;
		aLength=aFilePortion.Length();
		TChar tmp(aBuf[0]);
		if (tmp==' ')
			SearchForNonSpaceChar(aCharCount,aLength,aStartPos,aFilePortion,aBuf);
		}
	}

void CTestHierarchicalListBoxModel::SearchForFullTextString(TInt& aCharCount,TInt& aLength,TInt& aStartPos,
															TDes& aFilePortion,TDes& aText) const
	{
	TBuf<1> buf;
	while (++aCharCount<aLength)
		{
		buf=CharFromBuffer(aCharCount,aFilePortion);
		TChar tmp(buf[0]);
		if (tmp!=',')
			aText.Append(buf);
		else
			break;
		}
	if (aCharCount==aLength)
		{
		aStartPos+=aLength;
#if defined(_UNICODE)
		TBuf8<64> narrowBufferToReadFile;
		User::LeaveIfError(iFile.Read(aStartPos,narrowBufferToReadFile));
		aFilePortion.Copy(narrowBufferToReadFile);
#else
		User::LeaveIfError(iFile.Read(aStartPos,aFilePortion));
#endif
		aCharCount=-1;
		aLength=aFilePortion.Length();
		TChar tmp(buf[0]);
		if (tmp!=',')
			SearchForFullTextString(aCharCount,aLength,aStartPos,aFilePortion,aText);
		}
	}

TPtrC CTestHierarchicalListBoxModel::CharFromBuffer(TInt aCharPos,const TDesC& aBuffer) const
	{
	if (aCharPos==0)
		return aBuffer.Left(1);
	else if (aCharPos==aBuffer.Length())
		return aBuffer.Right(1);
	return aBuffer.Mid(aCharPos,1);
	}

void CTestHierarchicalListBoxModel::CreateItemL(TDes* aText,TInt aParentIndex,TInt aIndexOfSiblingToInsetAfter)
	{
	CHierListItem* item;
	item=new(ELeave) CHierListItem((TInt16)0);
	item->SetTextL(*aText);
	AddItemL(item,aParentIndex,aIndexOfSiblingToInsetAfter);
	aText->Zero();
	}

//
// class CSimpleControl
//

class CSimpleControl : public CCoeControl
    {
public:
	~CSimpleControl();
    void ConstructL();
	void SwitchListBoxesL(TInt aCommand);
private: // framework
	TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);
	void Draw(const TRect& /*aRect*/) const;
	TInt CountComponentControls() const;
	CCoeControl* ComponentControl(TInt aIndex) const;
private:
	void CreateDirTreeListBoxL();
	void CreateTestHierListBoxL();
	void CreateDirContentsListBoxL();
private:
	CEikDirectoryTreeListBox* iDirTreeListBox;
	CTestHierarchicalListBox* iHierListBox;
	CEikDirContentsListBox* iDirContentsListBox;
	CCoeControl* iFocusedControl;
    };

CSimpleControl::~CSimpleControl()
	{
	delete iDirTreeListBox;
	delete iHierListBox;
	delete iDirContentsListBox;
	}

void CSimpleControl::ConstructL()
    {
    CreateWindowL();
    Window().SetShadowDisabled(ETrue);
	Window().SetBackgroundColor(KRgbGray);
    SetExtentToWholeScreenL();
	CreateDirTreeListBoxL();
	CreateTestHierListBoxL();
	CreateDirContentsListBoxL();
    ActivateL();
    }

void CSimpleControl::CreateDirTreeListBoxL()
	{
	iDirTreeListBox=new(ELeave) CEikDirectoryTreeListBox;
	iDirTreeListBox->ConstructL(this,0,0);
	iDirTreeListBox->CreateListL(NULL);
	iDirTreeListBox->CreateScrollBarFrameL();
	iDirTreeListBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EOn);
	iDirTreeListBox->SetExtentL(TPoint(100,50),TSize(340,154));
	iDirTreeListBox->ActivateL();
	iDirTreeListBox->UpdateScrollBarsL();
	iDirTreeListBox->SetFocus(ETrue);
	iFocusedControl=iDirTreeListBox;
	}

void CSimpleControl::CreateTestHierListBoxL()
	{
	iHierListBox=new(ELeave) CTestHierarchicalListBox;
	iHierListBox->ConstructL(this);
	iHierListBox->CreateScrollBarFrameL();
	iHierListBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EOn);
	iHierListBox->SetExtentL(TPoint(100,50),TSize(340,154));
	iHierListBox->ActivateL();
	iHierListBox->UpdateScrollBarsL();
	iHierListBox->MakeVisible(EFalse);
	}

void CSimpleControl::CreateDirContentsListBoxL()
	{
	iDirContentsListBox=new(ELeave) CEikDirContentsListBox;
	iDirContentsListBox->ConstructL(this,EEikListBoxMultipleSelection,0);
	iDirContentsListBox->CreateScrollBarFrameL();
	iDirContentsListBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, CEikScrollBarFrame::EOn);
	iDirContentsListBox->SetExtentL(TPoint(100,50),TSize(340,154));
#if defined(__WINS__)
	iDirContentsListBox->SetPathL(_L("c:\\*"));
#else
	iDirContentsListBox->SetPathL(_L("z:\\*"));
#endif
	iDirContentsListBox->ActivateL();
	iDirContentsListBox->UpdateScrollBarsL();
	iDirContentsListBox->MakeVisible(EFalse);
	}

void CSimpleControl::SwitchListBoxesL(TInt aCommand)
	{
	CCoeControl* selectedList=NULL;
	switch (aCommand)
		{
	case EAppCmdDirContents:
		selectedList=iDirContentsListBox;
		break;
	case EAppCmdTestHier:
		selectedList=iHierListBox;
		break;
	case EAppCmdDirTree:
		selectedList=iDirTreeListBox;
		break;
		}
	if (selectedList && iFocusedControl!=selectedList)
		{
		iFocusedControl->MakeVisible(EFalse);
		iFocusedControl->SetFocus(EFalse);
		iFocusedControl=selectedList;
		iFocusedControl->SetFocus(ETrue);
		iFocusedControl->MakeVisible(ETrue);
		}
	}

TInt CSimpleControl::CountComponentControls() const
	{
	return 1;
	}

CCoeControl* CSimpleControl::ComponentControl(TInt aIndex) const
	{
	if (aIndex==0)
		return iFocusedControl;
	return NULL;
	}

void CSimpleControl::Draw(const TRect& aRect) const
	{
	CWindowGc& gc=SystemGc();
	gc.SetBrushColor(KRgbGray);
	gc.Clear(aRect);
	}

TKeyResponse CSimpleControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
    {
	iFocusedControl->OfferKeyEventL(aKeyEvent, aType);
    return(EKeyWasConsumed);
    }

//
// CSimpleAppUi
//

class CSimpleAppUi : public CEikAppUi
    {
public:
    void ConstructL();
	~CSimpleAppUi();
private: // framework
    void HandleCommandL(TInt aCommand);
private:
    CSimpleControl* iSimpleControl;
    };

void CSimpleAppUi::ConstructL()
    {
    BaseConstructL();
    iSimpleControl=new(ELeave) CSimpleControl;
    iSimpleControl->ConstructL();
    AddToStackL(iSimpleControl);
    }

CSimpleAppUi::~CSimpleAppUi()
	{
    delete iSimpleControl;
	}

void CSimpleAppUi::HandleCommandL(TInt aCommand)
    {
    switch (aCommand)
        {
	case EAppCmdDirContents:
	case EAppCmdTestHier:
	case EAppCmdDirTree:
		iSimpleControl->SwitchListBoxesL(aCommand);
		break;
	case EEikCmdExit:
		CBaActiveScheduler::Exit();
	default:
		;
		}
    }

//
// CSimpleDocument
//

class CSimpleDocument : public CEikDocument
	{
public:
	CSimpleDocument(CEikApplication& aApp): CEikDocument(aApp) { }
private: // from CApaDocument
	CEikAppUi* CreateAppUiL();
	};

CEikAppUi* CSimpleDocument::CreateAppUiL()
	{
    return(new(ELeave) CSimpleAppUi);
	}

//
// CSimpleApplication
//

class CSimpleApplication : public CEikApplication
	{
private: // from CApaApplication
	CApaDocument* CreateDocumentL();
	TUid AppDllUid() const;
	};

const TUid KUidSimpleApp={207};

TUid CSimpleApplication::AppDllUid() const
	{
	return(KUidSimpleApp);
	}

CApaDocument* CSimpleApplication::CreateDocumentL()
	{
	return(new(ELeave) CSimpleDocument(*this));
	}

//
// EXPORTed functions
//

EXPORT_C CApaApplication* NewApplication()
	{
	return(new CSimpleApplication);
	}

GLDEF_C TInt E32Dll(TDllReason)
	{
	return(KErrNone);
	}
