/******************************************************************************
 *
 * Copyright (c) 2000	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.
 *
 *
 *	Progman.cpp
 *
 *****************************************************************************/


// SOL++2000 
// 2000.03.20

#include <sol\ApplicationView.h>
#include <sol\Thread.h>
#include <sol\PopupView.h>
#include <sol\ListView.h>

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

#include "Resource.h"

#define WM_LISTUP	(WM_USER+200)

/**************************************************************************

  class ProgramScanner 

 */

class ProgramScanner :public Thread {
	PopupView	message;
	ImageList&	imageList;
	ListView&	listView;
	void		find(char* dir);
	void		addToListView(char* dir, char* fileName);
public:
	ProgramScanner(View* parent, ListView& listv, ImageList& image);
	void run();		
};


ProgramScanner::ProgramScanner(View* parent, ListView& listv, ImageList& image)
		:listView(listv),
		imageList(image)
{
	Args ar;
	ar.set(XmNwidth, 300);
	ar.set(XmNheight, 50);
	message.create(parent, "Scanning all programs(*.exe) on your hard disk!", ar);

}

void ProgramScanner::run()
{
	char path[10];
	char drive[10];
	DWORD d = ::GetLogicalDrives();
	Event event(0, 0, 0);
	Action action(NULL, event);
	message.popup(action);

	for(int i = 0; i<26; i++) {
		if(d & 1) {	
			sprintf(path, "%c:", 'A'+i);
			sprintf(drive, "%c:\\", 'A'+i);
			UINT driveType = GetDriveType(drive);
			if (driveType == DRIVE_FIXED) {
				find(path);
			} 
		}
		d = d >> 1;
	}
	message.popdown(action);
}


void ProgramScanner::find(char* dir)
{
	WIN32_FIND_DATA data;

	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) {
					char* subDir = new char[_MAX_PATH];
					sprintf(subDir, "%s\\%s", dir, data.cFileName);

					find(subDir);
					delete [] subDir;
				}
			} else {
				CharLower(data.cFileName);
				char* p = strstr(data.cFileName, ".exe");
				if (p) {
					addToListView(dir, data.cFileName);
				}
			}
		} while(::FindNextFile(fFile, &data)); 
		::FindClose(fFile);
	}
	delete [] buffer;

}

void ProgramScanner::addToListView(char* dir, char* fileName)
{
	// Extract an icon.
	char fullpath[_MAX_PATH];
	sprintf(fullpath, "%s\\%s", dir, fileName);

	HINSTANCE hInst = Application::getInstance();

	HICON hicon = ExtractIcon(hInst, fullpath, 0);
	if(hicon) {
		LV_ITEM item;
		memset(&item, 0, sizeof(LV_ITEM));

		// If it has an icon, add it ot the imageList.
		item.mask = LVIF_TEXT|LVIF_IMAGE;

		int id = imageList.addIcon(hicon);
		item.iImage	= id;
		
		item.pszText    = fullpath;	//fileName;
		item.cchTextMax = _MAX_PATH;
		listView.insertItem(&item);
		//Printf("Added Icond %s\r\n", fullpath);
	}
}


/**************************************************************************

   ProgramManager

 */

class ProgramManager :public ApplicationView {
	ProgramScanner* scanner;
	ImageList   imageList;
	ListView	listView;
	int			lastChangedItem;

	void	launch(Action& action);

	void	itemChanged(Action& action);

	long	close(Event& event);

	long	listup(Event& event);

	void	addToListView(char* dir, char* fileName);

	void	find(char* dir);

  public:
	ProgramManager(Application& applet, const char* name, Args& args);
	~ProgramManager();
};


ProgramManager::ProgramManager(Application& applet, const char* name, Args& args)
	:ApplicationView(applet, name, args),
		// Initialize an imageList to store an icon of size 32x32.
		imageList(32, 32, ILC_MASK, 0, 5)
{
	Args ar;
	ar.set(XmNstyle, (ulong)WS_CHILD|WS_VISIBLE|WS_BORDER|LVS_ICON);
	listView.create(this, "", ar);
	listView.setImageList(&imageList, LVSIL_NORMAL);

	// Add the listView to the default LayoutManager.
	add(listView);

	listView.addCallback(XmNdoubleClickCallback, this,
			(Callback)&ProgramManager::launch, NULL);

	listView.addCallback(XmNitemChangedCallback, this,
			(Callback)&ProgramManager::itemChanged, NULL);
	ar.reset();
	ar.set(XmNwidth, 300);
	ar.set(XmNheight, 50);


	lastChangedItem = -1;

	// Add a menucallback.
	addCallback(XmNmenuCallback, ID_EXIT, this, (Callback)&ProgramManager::exit, null);

	addEventHandler(WM_LISTUP, this, (Handler)&ProgramManager::listup, NULL);

	scanner = NULL;

	post(WM_LISTUP, 0, 0);

	restorePlacement();
}


ProgramManager::~ProgramManager()
{
	if (scanner) {
		scanner->terminate(0);
		scanner->wait();
		delete scanner;
		scanner = NULL;
	}
}


long ProgramManager::close(Event& event)
{
	imageList.clear();
	
	savePlacement();

	return defaultProc(event);
}


long ProgramManager::listup(Event& event)
{
	scanner = new ProgramScanner(this, listView, imageList);
	scanner ->start();
	return 0L;
}


void ProgramManager::launch(Action& action)
{
	if(lastChangedItem >= 0) {	
		char text[_MAX_PATH];
		listView.getItemText(lastChangedItem, 
							0, text, sizeof(text));
		Printf("WinExec %s\r\n", text);
		WinExec(text, SW_SHOW);
	}
}


void ProgramManager::itemChanged(Action& action)
{
	Event& event = action.getEvent();

	NM_LISTVIEW* nmlistv = (NM_LISTVIEW*)event.getLParam();
	lastChangedItem = nmlistv->iItem;
	if(lastChangedItem >= 0) {	
		char text[_MAX_PATH];
		listView.getItemText(lastChangedItem, 
							0, text, sizeof(text));
		char title[_MAX_PATH];
		sprintf(title, "ProgramManager - %s ", text);
		setText(title);
	}
}


// ProgramManager Main
void	Main(int argc, char** argv)
{
	const char* appClass = "ProgramManager";
	Application applet(appClass, argc, argv);
		
	Args args;
	ProgramManager programManager(applet, appClass, args);
	programManager.realize();
	applet.run();
}
