/**************************************************************************
 * FRMDSDIA.C - frm_dsdialog(): dynamic string dialog routine.
 *************************************************************************/

#include "gemfintl.h"
#include <string.h>

static char *default_buttons[] = {" Continue ",     NULL};
static char *default_strings[] = {"<no message>",   NULL};

/*-------------------------------------------------------------------------
 * Object tree for dynamic dialog box...
 *-----------------------------------------------------------------------*/

#define OUTLINED_BOX_SPEC 0x00021100L
#define SHADOWED_BOX_SPEC 0x00FF1100L

static OBJECT GFAR dialtree[] = {
  -1,  1, 21, G_BOX,	NONE,	OUTLINED, (_Ob_spec_t)0x00021100L,0x0000, 0x0000, 0x0021, 0x0017,
   2, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0001, 0x0001, 0x0001,
   3, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0002, 0x0001, 0x0001,
   4, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0003, 0x0001, 0x0001,
   5, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0004, 0x0001, 0x0001,
   6, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0005, 0x0001, 0x0001,
   7, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0006, 0x0001, 0x0001,
   8, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0007, 0x0001, 0x0001,
   9, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0008, 0x0001, 0x0001,
  10, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0009, 0x0001, 0x0001,
  11, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x000A, 0x0001, 0x0001,
  12, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x000B, 0x0001, 0x0001,
  13, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x000C, 0x0001, 0x0001,
  14, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x000D, 0x0001, 0x0001,
  15, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x000E, 0x0001, 0x0001,
  16, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x000F, 0x0001, 0x0001,
  17, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0010, 0x0001, 0x0001,
  18, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0011, 0x0001, 0x0001,
  19, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0012, 0x0001, 0x0001,
  20, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0013, 0x0001, 0x0001,
  21, -1, -1, G_STRING, NONE,	NORMAL,   (_Ob_spec_t)0L,		  0x0001, 0x0014, 0x0001, 0x0001,
   0, 22, 26, G_IBOX,	NONE,	NORMAL,   (_Ob_spec_t)0x00001100L,0x0001, 0x0015, 0x0001, 0x0001,
  23, -1, -1, G_BUTTON, 0x0005, NORMAL,   (_Ob_spec_t)0L,		  0x0000, 0x0000, 0x0001, 0x0001,
  24, -1, -1, G_BUTTON, 0x0005, NORMAL,   (_Ob_spec_t)0L,		  0x0000, 0x0000, 0x0001, 0x0001,
  25, -1, -1, G_BUTTON, 0x0005, NORMAL,   (_Ob_spec_t)0L,		  0x0000, 0x0000, 0x0001, 0x0001,
  26, -1, -1, G_BUTTON, 0x0005, NORMAL,   (_Ob_spec_t)0L,		  0x0000, 0x0000, 0x0001, 0x0001,
  21, -1, -1, G_BUTTON, 0x0025, NORMAL,   (_Ob_spec_t)0L,		  0x0000, 0x0000, 0x0001, 0x0001
  };

#define DIALSTL1 1		/* String Line 1				*/
#define DIALPBXB 21 	/* Parent Box for exit buttons	*/
#define DIALBX01 22 	/* First exit button			*/

/*----------------------------------------------------------------------------
 * count_strings - Count strings and keep track of the longest one.
 *--------------------------------------------------------------------------*/

#ifdef GEMFAST_PROTOS
  static short count_strings(char **pstrings, short maxstrings, short *pmaxlen)
#else
  static short count_strings(pstrings, maxstrings, pmaxlen)
	register char	**pstrings;
	register short	  maxstrings;
	short			  *pmaxlen;
#endif
{
	register short	  numstrings;
	register size_t   wrklen;
	register size_t   maxlen;

	for (numstrings = 0, maxlen = 0;
		 numstrings < maxstrings && *pstrings && **pstrings != 0x00;
		 ++numstrings,
		 ++pstrings) {

			if (maxlen < (wrklen = strlen(*pstrings))) {
				maxlen = wrklen;
			}
	}

	*pmaxlen = (short)maxlen;
	return numstrings;
}

/**************************************************************************
 * frm_dsdial - Form dynamic string dialog.
 *************************************************************************/

short frm_dsdialog(options, pbuttons, pstrings)
	long			 options;
	char			 *pbuttons[];
	char			 *pstrings[];
{
	short			   xbwidth;
	short			   slen;
	register short	   sizechar;
	register short	   counter;
	register short	   numobs;
	register short	   pixlen;
	register OBJECT  *ptree;
	register char	 **pwrk;
	static	 short	   initdone = 0;
	static	 short	   l1_title_y;
	static	 short	   l1_notitle_y;

/*-------------------------------------------------------------------------
 * validate the parameters.
 *-----------------------------------------------------------------------*/

	if (pstrings == NULL) {
		pstrings = default_strings;
	}

	if (pbuttons == NULL) {
		pbuttons = default_buttons;
	}

	if (!(options & FRM_NODEFAULTS)) {
		options |= (_FrmDefaults & FRM_DOPTIONBITS) | FRM_DEFAULT_DYNOPT;
	}
	options |= FRM_MANDATORY_DYNOPT;

/*-------------------------------------------------------------------------
 * Init the xywh values in the object tree, get the system character sizes
 * for later usage, precalc possible top-line Y placements for later.
 *-----------------------------------------------------------------------*/

	if (!initdone) {
		initdone = TRUE;
		rsc_treefix(dialtree);
		l1_notitle_y = dialtree[DIALSTL1].ob_y;
		l1_title_y	 = l1_notitle_y - (gl_hchar >> 1);
	}

/*-------------------------------------------------------------------------
 * Count the button strings, find the longest one, distribute the buttons
 * evenly within their parent box, make the rightmost the default button.
 * (We place a gutter of 2 character widths on each side of each button.)
 *-----------------------------------------------------------------------*/

	{
		short			saw_default_button = FALSE;
		char			*pbtn;
		register short	obx;

		numobs = count_strings(pbuttons, FRM_DSMAXBUTTONS, &slen);

		sizechar  = gl_wchar;
		pixlen	  = (slen + 2) * sizechar;
		sizechar *= 2;
		xbwidth   = (numobs * pixlen) + ((numobs + 1) * sizechar);

		for (counter = 0, obx = sizechar, pwrk = pbuttons, ptree = &dialtree[DIALBX01];
			 counter < FRM_DSMAXBUTTONS;
			 ++counter, obx += pixlen + sizechar, ++ptree) {

			ptree->ob_flags &= ~DEFAULT;

			if (counter < numobs) {
				pbtn = *pwrk++;
				ptree->ob_flags &= ~HIDETREE;
				ptree->ob_x 	= obx;
				if (*pbtn == 0x7F) {
					ptree->ob_flags |= DEFAULT;
					++pbtn;
					++saw_default_button;
				}
				ptree->_Ob_spec  = (_Ob_spec_t)pbtn;
				ptree->ob_width = pixlen;
			} else {
				ptree->ob_flags |= HIDETREE;
			}
		}

		if (!(options & FRM_DMUSTSELECT) && !saw_default_button) {
			if (options & FRM_DEFAULTLEFT) {
				numobs = 1; /* leftmost button is default								*/
			}
			dialtree[DIALPBXB+numobs].ob_flags |= DEFAULT;
		}
	}

/*-------------------------------------------------------------------------
 * Count the dialog strings, find the largest, calc the size of the
 * dialog box and the placement of the buttons at the bottom.  If space
 * permits, we leave a 1-line gutter between the last dialog string and
 * the buttons, but if all 20 dialog strings are used, then the buttons
 * are jammed right up against the bottom string.
 *-----------------------------------------------------------------------*/

	{
		register short btnadjust;

		numobs	  = count_strings(pstrings, FRM_DSMAXSTRINGS, &slen);

		btnadjust = (numobs < FRM_DSMAXSTRINGS); /* button padding, if space allows */

		pixlen	  = (slen + 2) * gl_wchar;
		pixlen	  = (pixlen > xbwidth) ? pixlen : xbwidth;

		sizechar  = gl_hchar;

		ptree			 = dialtree;
		ptree->ob_width  = pixlen;
		ptree->ob_height = ((numobs + 3 + btnadjust) * sizechar);

		ptree			 = &dialtree[DIALPBXB];
		ptree->ob_x 	 = (pixlen - xbwidth) >> 1;
		ptree->ob_y 	 = ((numobs + 1 + btnadjust) * sizechar) + (sizechar >> 2);
		ptree->ob_width  = xbwidth;
	}

/*-------------------------------------------------------------------------
 * Set the ob_width and ob_spec for all the active strings in the dialog
 * box, set all the inactive strings to HIDETREE.  Center strings that
 * start with 0x7F (and fix it so the 0x7F char isn't displayed).
 *-----------------------------------------------------------------------*/

	{
	register char *line;
	register short	at_x;
	register short	len;

		sizechar = gl_wchar;
		for (counter = 0, pwrk	= pstrings, ptree = &dialtree[DIALSTL1];
			 counter < FRM_DSMAXSTRINGS;
			 ++counter, ++ptree) {

			if (counter < numobs) {
				ptree->ob_flags &= ~HIDETREE;
				line = *pwrk++;
				if (*line == 0x7F) {
					len  = sizechar * (short)strlen(++line);
					at_x = (pixlen - len) / 2;
				} else {
					len  = pixlen;
					at_x = sizechar;
				}
				ptree->_Ob_spec   = (_Ob_spec_t)line;
				ptree->ob_x 	 = at_x;
				ptree->ob_width  = len;

			} else {
				ptree->ob_flags |= HIDETREE;
			}
		}
	}

/*-------------------------------------------------------------------------
 * Handle the FRM_DSHADOWED and FRM_DSL1TITLE options.
 *-----------------------------------------------------------------------*/

	ptree  = dialtree;

	if (options & FRM_DSHADOWED) {
		ptree->ob_state = SHADOWED;
		ptree->_Ob_spec  = (_Ob_spec_t)SHADOWED_BOX_SPEC;
	} else {
		ptree->ob_state = OUTLINED;
		ptree->_Ob_spec  = (_Ob_spec_t)OUTLINED_BOX_SPEC;
	}

	ptree[DIALSTL1].ob_y =
		(options & FRM_DSL1TITLE) ? l1_title_y : l1_notitle_y;


/*-------------------------------------------------------------------------
 * Do dialog, return button number adjusted to range of 0-4.
 *-----------------------------------------------------------------------*/

	{
		short selection;

		selection = frm_dialog(options, ptree, ROOT);
		return (selection - DIALBX01);

	}
}

