#include <xmObject.h>
#include <strstream.h>
#include <stream.h>
#include <string.h>

#define MAXENTRIES 20

// class declarations ////////////////////////////////////////////////////////////

class PhoneEntry
{
friend class XmPhoneBook;
friend class PhoneDialog;
	char name[30];
	char firstName[20];
	char street[30];
	char zip[10];
	char city[20];
	char country[20];
	char phoneNo[15];
	bool isCompany;

	PhoneEntry();
};

class XmPhoneBook : public XmWindow
{
	PhoneEntry* entries[MAXENTRIES];
	int curEntry, entryCount;
	bool editNew;

//	bool XmPhoneBook::initWindowSize(int& x, int& y, int& w, int& h)	{ w = 400; h = 400; return(TRUE); }

	void createMenu();

	void processEntry(char*);
	void showMemoryUsage(void*);
	void sorry(char*);
	void quit(void*);
public:
	XmPhoneBook();

	void initialize();
	void gnuInit()						{ setInitWindowSize(300, 300, 400, 400); XmPhoneBook::initialize(); }
	void updateCurEntry(bool);
};

class PhoneDialog : public XmUserDialog
{
	XmPhoneBook* phoneBook;
	PhoneEntry* entry;

//	bool PhoneDialog::initWindowSize(int& x, int& y, int& w, int& h)	{ w = 587; h = 304; return(TRUE); }
	void createContents();
	void initContents();

	void setEntryType(XmRadioButton*);
	void dlgOk(void*);
	void dlgCancel(void*);
public:
	PhoneDialog(XmPhoneBook* parent, PhoneEntry* e) : XmUserDialog("Phone Book Entry", parent, XmSdlgAppModal)
	{ phoneBook = parent; entry = e; destroyOnDelete(); }

	void gnuInit()	{ setInitWindowSize(300, 300, 587, 304); PhoneDialog::createContents(); PhoneDialog::initContents(); realize(); }
};

// member functions ////////////////////////////////////////////////////////////////

PhoneEntry::PhoneEntry()
{
	strcpy(name, "New.");
	*firstName = *street = *zip = *city = *country = *phoneNo = 0;
	isCompany = FALSE;
}

XmPhoneBook::XmPhoneBook() : XmWindow("Xm++ Phone Book")
{
	curEntry = -1;
	entryCount = 0;
	editNew = FALSE;
}

void XmPhoneBook::initialize()
{
	createMenu();
	addSubpane(ListBox, "PhoneList");
	listBox("PhoneList")->add("No entries.");
//	listBox("PhoneList")->setCallback(cb(defaultAction), this, CB(XmPhoneBook::processEntry), TRUE, CB_OBJ_NAME);
}

void XmPhoneBook::createMenu()
{
	XmDropdownMenu* menu = createDropdownMenu();

	menu->addLabels("&File", "&Entry", "&Misc", NULL);

	menu->setCurrentLabel("File");
	menu->addItems(	Entry("&Open...", CB(XmPhoneBook::sorry)), 
					Entry("&Save", CB(XmPhoneBook::sorry)), 
					Entry("Save &As...", CB(XmPhoneBook::sorry)), NULLENTRY);
	menu->addSeparator();
	menu->addItems(	Entry("E&xit", CB(XmPhoneBook::quit)), NULLENTRY);
	menu->setCurrentLabel("Entry");
	menu->addItems(	Entry("&New", CB(XmPhoneBook::processEntry)), 
					Entry("&Edit", CB(XmPhoneBook::processEntry)), 
					Entry("&Delete", CB(XmPhoneBook::processEntry)), NULLENTRY);
	menu->setCurrentLabel("Misc");
	menu->addItems(	Entry("&Memory usage", CB(XmPhoneBook::showMemoryUsage)), NULLENTRY);

}

void XmPhoneBook::processEntry(char* cmd)
{
	PhoneEntry* anEntry;
	XmListBox* list = listBox("PhoneList");

	curEntry = -1;
	switch(*cmd)
	{	case 'N':
 		entries[entryCount++] = anEntry = new PhoneEntry;
		curEntry = entryCount;
		if(entryCount == 1)
			list->remove(1);
		list->add("New...");
		editNew = TRUE;

		case 'E':
		case 'P':
		if(curEntry < 0 && (curEntry = list->selectedIndex()) <= 0)
			break;
		(new PhoneDialog(this, entries[curEntry - 1]))->gnuInit();	// open();
		break;

		case 'D':
		if((curEntry = list->selectedIndex()) <= 0)
			break;
		list->remove(curEntry);
		delete entries[curEntry - 1];
		for(int i = curEntry - 1; i < entryCount - 1; i++)
			entries[i] = entries[i + 1];
		entryCount--;
		curEntry = -1;
		if(!entryCount)
			list->add("No entries.");
		break;
	}
}

void XmPhoneBook::updateCurEntry(bool ok)
{
	if(curEntry != -1)
	{	XmListBox* list = listBox("PhoneList");
		if(ok)
		{	ostrstream txt;
			PhoneEntry* anEntry = entries[curEntry - 1];
			txt << anEntry->name << " " << anEntry->firstName
				<< " -> " << anEntry->phoneNo;
			txt.put(0);
			list->remove(curEntry);
			list->insert(curEntry, txt.str());
		}
		else
		{	if(editNew)
			{	list->selectIndex(curEntry);
				processEntry("Delete");
			}
		}
	}
	editNew = FALSE;
}

#include <malloc.h>

void XmPhoneBook::showMemoryUsage(void*)
{
	ostrstream msg;
#ifdef HP
	struct mallinfo mi = mallinfo();

	msg << "current memory usage: \n"
		<< " total: " << mi.arena << "\n"						/* total space in arena */
//		<< " no. ord. Blocks : " << mi.ordblks << " \n"			/* number of ordinary blocks */
//		<< " no. small Blocks : " << mi.smblks  << " \n"		/* number of small blocks */
//		<< " space hold Blk. Hdrs. : " << mi.hblkhd  << " \n"	/* space in holding block headers */
//		<< " no. hold. Blk. Hdrs. : " << mi.hblks  << " \n"		/* number of holding blocks */
//		<< " space small Blocks : " << mi.usmblks  << " \n"		/* space in small blocks in use */
//		<< " free small Blocks : " << mi.fsmblks  << " \n"		/* space in free small blocks */
		<< " space ord. Blocks : " << mi.uordblks  << " \n"		/* space in ordinary blocks in use */
		<< " free ord. Blocks : " << mi.fordblks  << " \n"		/* space in free ordinary blocks */
//		<< " space penality : " << mi.keepcost  << " \n"		/* space penalty if keep option */
;
#else
	msg << "Sorry, not available.";
#endif
	msg.put('\0');
	(new XmMsgBox(msg.str(), "System Info", XmSdlgAppModal | XmSmsgInfo | XmSmsgOk))->showMsg();
}

void XmPhoneBook::sorry(char* cmd)
{
	(new XmMsgBox("Sorry, not implemented.", cmd, XmSdlgAppModal | XmSmsgInfo | XmSmsgOk, this))->showMsg();
}

extern "C" { void exit(int); }

void XmPhoneBook::quit(void*)
{
	exit(0);
}

void PhoneDialog::createContents()
{
	add((new XmGroupBox("prType", 14, 18, 150, 94))->setText("Type"));
	add((new XmRadioButton("ctrTypePerson", 38, 48, 88, 20))->setText("Person"));
	add((new XmRadioButton("ctrTypeCompany", 38, 72, 98, 20))->setText("Company"));
	add((new XmStaticText("prName", 206, 36, 52, 16, XmSright))->setText("Name"));
	add((new XmEdit("name", 268, 30, 282, 24, XmSautohscroll)));
	add((new XmStaticText("prFirstName", 172, 68, 78, 16, XmSright))->setText("First name"));
	add((new XmEdit("firstName", 268, 66, 224, 24, XmSautohscroll)));
	add((new XmStaticText("prStreet", 202, 104, 48, 16, XmSright))->setText("Street"));
	add((new XmEdit("street", 268, 100, 284, 24, XmSautohscroll)));
	add((new XmStaticText("prZip", 208, 144, 40, 16, XmSright))->setText("ZIP"));
	add((new XmEdit("zip", 268, 140, 64, 24, XmSautohscroll)));
	add((new XmStaticText("prCity", 350, 144, 34, 16))->setText("City"));
	add((new XmEdit("city", 390, 140, 164, 24, XmSautohscroll)));
	add((new XmStaticText("prCountry", 180, 186, 64, 16, XmSright))->setText("Country"));
	add((new XmComboBox("country", 268, 180, 286, 80)));
	add((new XmGroupBox("prPhone", 14, 126, 152, 80))->setText("Phone No."));
	add((new XmEdit("phone", 26, 166, 130, 24, XmSautohscroll)));
	add((new XmPushButton("ctrOk", 334, 230, 80, 28))->setText("OK"));
	add((new XmPushButton("ctrCancel", 436, 230, 80, 28))->setText("Cancel"));
}


void PhoneDialog::initContents()
{
	edit("name")->setText(entry->name);
	edit("firstName")->setText(entry->firstName);
	edit("street")->setText(entry->street);
	edit("zip")->setText(entry->zip);
	edit("city")->setText(entry->city);
	edit("phone")->setText(entry->phoneNo);
	comboBox("country")->setText(entry->country);
	comboBox("country")->addAll("Austria", "Germany", "USA", NULL);


	char* bname = entry->isCompany ? "ctrTypeCompany" : "ctrTypePerson";
	XmRadioButton* aButton = radioButton(bname);
	aButton->setState(TRUE);
	setEntryType(aButton);

	radioButton("ctrTypePerson")->setCallback(this, CB(PhoneDialog::setEntryType));
	radioButton("ctrTypeCompany")->setCallback(this, CB(PhoneDialog::setEntryType));

	pushButton("ctrOk")->setCallback(this, CB(PhoneDialog::dlgOk));
	pushButton("ctrCancel")->setCallback(this, CB(PhoneDialog::dlgCancel));
}

void PhoneDialog::setEntryType(XmRadioButton* cmd)
{
	if(!strcmp(cmd->getName(), "ctrTypeCompany"))
	{	edit("firstName")->setText("");
		disable("prFirstName", "firstName", NULL);
	}
	else
		enable("prFirstName", "firstName", NULL);
}

void PhoneDialog::dlgOk(void*)
{
	strcpy(entry->name, edit("name")->getText());
	strcpy(entry->firstName, edit("firstName")->getText());
	strcpy(entry->street, edit("street")->getText());
	strcpy(entry->zip, edit("zip")->getText());
	strcpy(entry->city, edit("city")->getText());
	strcpy(entry->country, comboBox("country")->getText());
	strcpy(entry->phoneNo, edit("phone")->getText());
	entry->isCompany = radioButton("ctrTypeCompany")->getState();
	phoneBook->updateCurEntry(TRUE);
	delete this;
}

void PhoneDialog::dlgCancel(void*)
{
	phoneBook->updateCurEntry(FALSE);
	delete this;
}


// application init function ////////////////////////////////////////////

void XmApp::initialize()
{
	(new XmPhoneBook)->gnuInit();		// initialize();
};

