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

// SOL++2000
// 2001/03/19 Added getPreferredSize method.
// 2001/03/29 Modified setValues method.

#include <sol\ComboBox.h>


// 2001/03/29 Added CBS_AUTOHSCROLL style
static const long STYLE = (const long)(WS_TABSTOP|WS_VSCROLL|CBS_NOINTEGRALHEIGHT|CBS_AUTOHSCROLL);

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

const int ComboBox::heightMargin = 2;

Arg ComboBox::styles[] = {
	{XmNsortItems, 	     CBS_SORT},
	{XmNdisableNoScroll, CBS_DISABLENOSCROLL},
	{XmNoemConvert,      CBS_OEMCONVERT}
};


ComboBox::ComboBox(View* parent, const char* name, Args& args)
	:Primitive(parent, name, 
			args.set(styles, XtNumber(styles))
			    .set(XmNpredefined, TRUE)
			    .set(XmNstyle, (ulong)STYLE)
			    .set(XmNclassName, (ulong)"ComboBox"))

{
	setValues(args);
}


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

	setValues(args);

	return rc;
}


Arg* ComboBox::getCallbackTable(int* num)
{
	static Arg table[] = {
	{XmNcloseUpCallback,		CBN_CLOSEUP},
 	{XmNdefaultActionCallback,	CBN_DBLCLK},
 	{XmNdropDownCallback,		CBN_DROPDOWN},
	{XmNeditChangeCallback,		CBN_EDITCHANGE},
	{XmNeditUpdateCallback,		CBN_EDITUPDATE},
	{XmNerrorSpaceCallback,		(ulong)CBN_ERRSPACE},

	{XmNkillFocusCallback,		CBN_KILLFOCUS},
	{XmNselChangeCallback,		CBN_SELCHANGE},
	{XmNselEndCancelCallback,	CBN_SELENDCANCEL},
	{XmNselEndOkCallback,		CBN_SELENDOK},
	{XmNsetFocusCallback,		CBN_SETFOCUS}
	};

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


void ComboBox::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();
		// 2001/03/31
		// Compute the length of string buffer to store all 
		// item-texts separated with a new line .
		for(int n = 0; n< count; n++) {
			buffLen = buffLen + getLBTextLen(n) + 1; //strlen("\n");	
		} 

		char* list = new char[buffLen];
		*list      = NULL;
		char* buff = list;
		for(int i = 0; i< count; i++) {
			int len = getLBTextLen(i);
			getLBText(i, buff);
			buff += len;
			
			if(i < count -1) {
				*buff = itemsListDelim;
			}
			buff++;
		}
		*buff = Zero;
		*val  = (ulong)list;
	}
}


// 2001/03/29
void ComboBox::setValues(Args& args)
{	
	ulong v;
	if (!args.get(XmNwidth, &v) ) {
		args.set(XmNwidth, 100);
	}
	if (!args.get(XmNheight, &v) ) {
		args.set(XmNheight, 100);
	}
	

	Primitive::setValues(args);

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

	/*
	*/
	
	ulong  val;
	if (args.get(XmNmaxLength, &val))
		limitText((int)val);

	if (args.get(XmNlabelString, &val))
		setText((char*)val);

	// XmNitems & XmNitemCount;
	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* item = (char*)val;
		list = new char[strlen(item)+1];
		strcpy(list, item);
	}

	if (list) {
		char* str = list;
		char* ptr = list;
		while(*ptr) {
			if(*ptr == itemsListDelim) {	//2001/04/01
				*ptr++ = NULL;
				addString(str);
				str = ptr;
			}
			else {
				ptr++;
			}
		}
		if(str)  addString(str);
		if(list) delete[] list;
	}
}


// List up long file names.
void ComboBox::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 ComboBox::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;
	ComboBox::findFiles(attr, pattern);	
}

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


// 2001/03/19
void ComboBox::getPreferredSize(Dimension& d)
{
	int w, h;
	getSize(w, h);

	LONG style   = getWindowLong(GWL_STYLE);
	if ((style & CBS_DROPDOWN) ||
		(style & CBS_DROPDOWNLIST )) {
		h = getControlHeight() + heightMargin;
	}
	d.set(w, h);
}

