/******************************************************************************
 *
 * Copyright (c) 1999	TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 *  
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *	Dirtreev.cpp
 *
 *****************************************************************************/

// SOL++2000
// 2000.02.18


#include <direct.h>
#include <sol\Stdio.h>

#include "dirtreev.h"


DirTreeView::DirTreeView(View* parent, const char* name, Args& args)
	:TreeView(parent, name, args)
{
	homeNode     = NULL;
	hcurrentNode = NULL;
	popupMenu = null;
	

	addCallback(XmNrightClickCallback, this,
		(Callback)&DirTreeView::rightClick, null);
}


char* DirTreeView::doubleClick(Action& action)
{			
	POINT pt;
	getCursorPos(&pt);
	toClient(&pt);

	TV_HITTESTINFO ht;
	memset(&ht, 0, sizeof(ht));

	ht.pt = pt;

	HTREEITEM htItem = hitTest(&ht);
	if(htItem && (ht.flags & TVHT_ONITEMBUTTON)) {
		return NULL;
	}
	
	if(htItem && (ht.flags & TVHT_ONITEMLABEL)) {
		hcurrentNode = htItem;

		char buffer[256];
		TV_ITEM xitem;
		xitem.pszText = buffer;
		xitem.cchTextMax = sizeof(buffer);
		xitem.mask = TVIF_TEXT|TVIF_PARAM;
		xitem.hItem = htItem;

		getItem(&xitem);
		static char buff[1000];
		buff[0] = NULL;
		getHierachy(xitem.hItem, buff, "\\");
		return buff;
	}
	return NULL;
}


void DirTreeView::rightClick(Action& action)
{
	Printf("Popup right-button menu\r\n");
	popupMenu -> track();
	Printf("Selected \r\n");

}


void  DirTreeView::selChanged(Action& action)
{			
	Event& event = action.getEvent();
	LPARAM lParam = event.getLParam();

	NM_TREEVIEW* treev = (NM_TREEVIEW*)lParam;
	
	hcurrentNode = treev->itemNew.hItem;

//	if(htItem && (ht.flags & TVHT_ONITEMLABEL)) {
	char buffer[256];
	TV_ITEM xitem;
	xitem.pszText = buffer;
	xitem.cchTextMax = sizeof(buffer);
	xitem.mask = TVIF_TEXT|TVIF_PARAM;
	xitem.hItem = hcurrentNode;

	getItem(&xitem);

	static char buff[1000];
	buff[0] = Zero;
	getHierachy(xitem.hItem, buff, "\\");
//	return buff;

}


// Add an item to a treeview.

HTREEITEM DirTreeView::addItem(HTREEITEM parent, HTREEITEM after, 
								   char* text)
{
	TV_ITEM item;
	TV_INSERTSTRUCT insertStruct;
	memset(&item, 0, sizeof(TV_ITEM));
	memset(&insertStruct, 0, sizeof(TV_INSERTSTRUCT));
	item.mask = TVIF_TEXT;
	item.pszText = text;
 
	insertStruct.item = item;
	insertStruct.hInsertAfter = after;
	insertStruct.hParent = parent;
	return insertItem(&insertStruct);
}


// Add an item to a treeview.
HTREEITEM DirTreeView::addItemWithFlag(HTREEITEM parent, HTREEITEM after, 
								   char* text, BOOL readable)
{
	TV_ITEM item;
	TV_INSERTSTRUCT insertStruct;
	memset(&item, 0, sizeof(TV_ITEM));
	memset(&insertStruct, 0, sizeof(TV_INSERTSTRUCT));
	item.mask = TVIF_TEXT|TVIF_PARAM;
	item.pszText = text;
    item.lParam  = readable;

	insertStruct.item = item;
	insertStruct.hInsertAfter = after;
	insertStruct.hParent = parent;
	return insertItem(&insertStruct);
}


// Build a tree struction of directories.
void DirTreeView::findDirectories(HTREEITEM parent, char* dir,
				  int ini, int max)
{
	if(ini < max) {
		WIN32_FIND_DATA data;
		HTREEITEM item = (HTREEITEM)TVI_FIRST;

		char* buffer = new char[_MAX_PATH];

		sprintf(buffer, "%s\\*", dir);
		HANDLE fFile= ::FindFirstFile(buffer, &data);

		if(fFile != INVALID_HANDLE_VALUE) {
			do {
				if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
					if (strcmp(".", data.cFileName) != 0 && strcmp("..", data.cFileName) != 0) {
						item = addItem(parent, item, data.cFileName);
						char* subDir = new char[_MAX_PATH];
						sprintf(subDir, "%s\\%s", dir, data.cFileName);
				
						findDirectories(item, subDir,
							(ini+1), max);
						delete [] subDir;
					}
				}
			} while(::FindNextFile(fFile, &data)); 
			::FindClose(fFile);
		}
		delete [] buffer;
	}
}


void DirTreeView::buildHierachy(HTREEITEM parent, char* dir)
{
	HTREEITEM item = (HTREEITEM)TVI_FIRST;
	if(dir) {
		char* slash = strchr(dir, '/');
		if(slash) {
			*slash++ = NULL;
		}
		item = addItem(parent, item, dir);
		homeNode = item;
		if(slash && strlen(slash)) {	 
				buildHierachy(item, slash);
		}
	}
}


// Remove all children of a node and the siblings.
void DirTreeView::deleteChildren(HTREEITEM htreeItem)
{
	HTREEITEM child = getChild(htreeItem);
	while(child) {
		HTREEITEM sibling = getNextSibling(child);
		// We have to free the member of lParam?
		deleteItem(child);
		child = sibling;
	}
}


// Expand all children of a node and the siblings.
void DirTreeView::expandChildren(HTREEITEM htreeItem, DWORD flag)
{
	HTREEITEM child = getChild(htreeItem);
	while(child) {
		HTREEITEM sibling = getNextSibling(child);
		expand(child, flag);
		expandChildren(child, flag);
		child = sibling;
	}
}



HTREEITEM DirTreeView::getLeaf()
{ 
	HTREEITEM child = getRoot();

	while(child) {
		HTREEITEM next = getChild(child);
		if(next == NULL) {
			break;
        }
		else {
			child = next;
		}
	}
	return child;
}


// Get a fullpath name of a dirnode.
void DirTreeView::getHierachy(HTREEITEM selItem, 
							  char* buff, char* delim)
{
	TV_ITEM hitem;

	HTREEITEM parent = getParent(selItem);
	if(parent) {
		getHierachy(parent, buff, delim);
		char* text       = new char[_MAX_PATH];
		hitem.mask       = TVIF_TEXT|TVIF_HANDLE;
		hitem.hItem      = selItem;
		hitem.pszText    = text;
		hitem.cchTextMax = _MAX_PATH;
		getItem(&hitem);
		strcat(buff, delim);
		strcat(buff, text);
		delete [] text;
	}
	else {
		char* text       = new char[_MAX_PATH];
		hitem.mask       = TVIF_TEXT|TVIF_HANDLE;
		hitem.hItem      = selItem;
		hitem.pszText    = text;
		hitem.cchTextMax = _MAX_PATH;
		getItem(&hitem);
		strcat(buff, text);
		delete [] text;
	}
}
