/******************************************************************************
 *
 * 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.
 *
 *
 *	ListBox.cpp
 *
 *****************************************************************************/

// SOL++2000
// 2001/04/01 Modified getValues and setValues.

#include <sol\ListBox.h>


static const long STYLE = (WS_TABSTOP|WS_BORDER|LBS_NOTIFY|WS_HSCROLL|WS_VSCROLL|\
				LBS_NOINTEGRALHEIGHT);

const char ListBox::itemsListDelim = '\n';

// Used only in constructor.

Arg ListBox::styles[] = {
	{XmNdisableNoScroll,   LBS_DISABLENOSCROLL},
	{XmNextendedSel,       LBS_EXTENDEDSEL},
	{XmNmultiColumn,       LBS_MULTICOLUMN},
	{XmNmultipleSel,       LBS_MULTIPLESEL},
	{XmNsortItems,         LBS_SORT},
	{XmNuseTabStops,       LBS_USETABSTOPS},
	{XmNwantKeyboardInput, LBS_WANTKEYBOARDINPUT},
};


ListBox::ListBox(View* parent, const char* name, Args& args)
	:Primitive(parent, name, 
			args.set(styles, XtNumber(styles))
			    .set(XmNpredefined, TRUE)
			    .set(XmNstyle,     (ulong)STYLE)
			    .set(XmNexStyle,   (ulong)WS_EX_CLIENTEDGE)
			    .set(XmNclassName, (ulong)"ListBox"))
{
	setValues(args);
}



Boolean ListBox::create(View* parent, const char* name, Args& args)
{
	Boolean rc = Primitive::create(parent, name, 
			args.set(styles, XtNumber(styles))
			    .set(XmNpredefined, TRUE)
			    .set(XmNstyle,     (ulong)STYLE)
			    .set(XmNexStyle,   (ulong)WS_EX_CLIENTEDGE)
			    .set(XmNclassName, (ulong)"ListBox"));

	setValues(args);

	return rc;
}


Arg* ListBox::getCallbackTable(int* num)
{
	static Arg table[] = {
	{XmNdefaultActionCallback, 	LBN_DBLCLK},
	{XmNerrorSpaceCallback,		(ulong)LBN_ERRSPACE},
	{XmNkillFocusCallback,		LBN_KILLFOCUS},
	{XmNselCancelCallback,		LBN_SELCANCEL},
 	{XmNselChangeCallback,		LBN_SELCHANGE},
 	{XmNsetFocusCallback,		LBN_SETFOCUS},
 	};

	*num = XtNumber(table);
	return table;
}

int	ListBox::getCurText(char* buffer) 
{
	if(buffer) {
		*buffer = Zero;
		int indx = getCurSel();
		if(indx != LB_ERR) {
			return getText(indx, buffer);
		}
		else {
			return 0;
		}
	}
	return 0;
}


char* ListBox::getCurText()
{
	char* text = NULL;

	int indx = getCurSel();
	if(indx != LB_ERR) {
		int len = getTextLen(indx);
		text = new char[len+1];
		getText(indx, text);
	}
	return text;
}

void ListBox::getValues(Args& args)
{
	Primitive::getValues(args);

	getStyle(args, styles, XtNumber(styles));

	ulong* val = (ulong*)args.get(XmNitemsList);
	if(val) {
		int buffLen = 0;
		int count  = getCount();
		for(int n = 0; n< count; n++) {
			buffLen = buffLen + getTextLen(n) + 1; //strlen("\n");
		}

		char* list = new char[buffLen];
		*list      = NULL;
		char* buff = list;

		for(int i = 0; i< count; i++) {
			int len = getTextLen(i);
			getText(i, buff);
			buff += len;
			if(i < count -1) {
				*buff  = itemsListDelim;
			}
			buff++;
		}
		*buff = Zero;

		*val  = (ulong)list;
	}
}


void ListBox::setValues(Args& args)
{
	Primitive::setValues(args);

	updateStyle(args, styles, XtNumber(styles));

	ulong  val;
	char** items = NULL;
	int     count = 0;
	if (args.get(XmNitemCount, &val))
		count = (int)val;
	if (args.get(XmNitems, &val))
		items = (char**)val;
	if (count >0 && items) {
		resetContent();
		for (int i = 0; i<count; i++) {
			addString(items[i]);
		}
	}

	// XmNitemsList

	char* list = NULL;
	if (args.get(XmNitemsList, &val)) {
		resetContent();
		char* s = (char*)val;
		list = new char[strlen(s)+1];
		strcpy(list, s);
	}
	if (list) {
		char* str = list;
		char* ptr = list;
		while(*ptr) {
			if(*ptr == itemsListDelim) {
				*ptr++ = NULL;
				addString(str);
				str = ptr;
			}
			else {
				ptr++;
			}
		}
		if (str)  addString(str);
		if (list) delete list;
	}
}


// List up long file names.
void ListBox::findFiles(DWORD attr, const char* pattern)
{
	WIN32_FIND_DATA data;
	HANDLE hf = ::FindFirstFile(pattern, &data);
	if(hf != INVALID_HANDLE_VALUE) {
		do {
			if(data.dwFileAttributes & attr) {
				addString((char*)data.cFileName);
			}			
		} while(::FindNextFile(hf, &data));
		::FindClose(hf);
	}
}


void ListBox::findFiles(const char* pattern)
{
	DWORD attr = FILE_ATTRIBUTE_ARCHIVE|
		FILE_ATTRIBUTE_DIRECTORY|
		FILE_ATTRIBUTE_COMPRESSED|
		FILE_ATTRIBUTE_HIDDEN| 
		FILE_ATTRIBUTE_NORMAL|	
		FILE_ATTRIBUTE_READONLY| 
		FILE_ATTRIBUTE_SYSTEM;
	ListBox::findFiles(attr, pattern);	
}

// Find all subdirectories under dir.
// Give a string such as "c:\\windows"  for dir.
void ListBox::findDirectories(const char* dir)
{
	char pattern[_MAX_PATH];
	wsprintf(pattern, "%s\\*.*", dir);
	findFiles(FILE_ATTRIBUTE_DIRECTORY, pattern);
}
