#include "xf86config.h"
#include "util.h"

/*
 * Keyboard configuration.
 */
int
KeyBoard::xmodmap_configuration()
{
    int rc;

    while (1) {
	rc = dialog_yesno(TITLE,
"If you want your keyboard to generate non-ASCII characters in X, because\n"
"you want to be able to enter language-specific characters, you can set\n"
"the left Alt key to Meta, and the right Alt key to ModeShift.\n"
"\n"
"Do you want to enable these bindings for the Alt keys?", -1, -1);

	if (rc == 0)
	    altmeta = 1;
	else if (rc < 0)
	    break;

	done();
	return 1;
    }
    return 0;
} /* xmodmap_configuration */


/*
 * Configuration of XKB 
 */

/* 
 * Add here combinations of symbols and geometry for keyboards
 * This will be annotated with "en_US" and "+..." later
 */

struct sympart1 {
     int usonly;     /* 0=us or us_EN, 1=us */
     char *symname;
     char *geoname;
} sym1struct;

static ListItem sympart1[] = {
	{ "0+pc101+pc",			"Standard 101-key keyboard" },
	{ "0+pc102+pc",			"Standard 102-key keyboard" },
	{ "1+pc101euro+pc",		"101-key with ALT_R = Multi_key" },
	{ "1+pc102euro+pc",		"102-key with ALT_R = Multi_key" },
	{ "1+microsoft+microsoft",	"Microsoft Natural keyboard" },
	{ "1+pc101+keytronic(FlexPro)",	"KeyTronic FlexPro keyboard" },
	{ "0+pc101+pc",			"DEFAULT" },
};
#define NSYM1	(sizeof sympart1 / sizeof sympart1[0])

struct sympart2 {
    char *prefix;   /* us or us_en */
    char *extend;   /* +de, +fr, ... */
} sym2struct;

static ListItem sympart2[] = {
	{	"en_US",	"DEFAULT",			},
	{	"en_US+be",	"Belgium",			},
	{	"en_US+bg",	"Bulgaria",			},
	{	"en_US+ca",	"Canada",			},
	{	"en_US+cs",	"Czechoslovakia",		},
	{	"en_US+dk",	"Denmark",			},
	{	"en_US+fi",	"Finland",			},
	{	"en_US+fr",	"France",			},
	{	"en_US+de",	"Germany",			},
	{	"en_US+it",	"Italy",			},
	{	"en_US+no",	"Norway",			},
	{	"en_US+pl",	"Poland",			},
	{	"en_US+pt",	"Portugal",			},
	{	"en_US+ru",	"Russia",			},
	{	"en_US+es",	"Spain",			},
	{	"en_US+se",	"Sweden",			},
	{	"en_US+th",	"Thailand",			},
	{	"en_US+fr_CH",	"Switzerland/French layout",	},
	{	"en_US+de_CH",	"Switzerland/German layout",	},
	{	"en_US+gb",	"United	Kingdom",		},
	{	"us",		"USA",				},
};

#define NSYM2	(sizeof sympart2 / sizeof sympart2[0])

int
KeyBoard::composekeymaps()
{
    int i;
    int rc;
    int xkbsym1, xkbsym2;

    /* this is entered when the user did not find a preconfigured 
     * XkbKeymap 
     */
    while (1) {
	static char sym1text[80];

	rc = Xmenu(TITLE,
    "You did not select one of the preconfigured keymaps. We will now try to\n"
    "compose a suitable XKB setting. This setting is untested.  Please select\n"
    "one of the following standard keyboards. Use DEFAULT if nothing really\n"
    "fits (101-key, tune manually)",
			    8, sympart1, NSYM1, 0, 0);

	if (rc < 0)
	    return 0;
	else
	    xkbsym1 = rc;

	while (1) {
	    rc = Xmenu(TITLE,
	"Please choose one of the following countries. Use DEFAULT if nothing\n"
	"really fits (US encoding, tune manually)",
				8, sympart2, NSYM2, 0, 0);

	    if (rc < 0)
		break;
	    else
		xkbsym2 = rc;

	    strcpy(sym1text, sympart1[xkbsym1].id);
	    sym1struct.usonly = atoi(strtok(sym1text, "+"));
	    sym1struct.symname = strtok(NULL, "+");
	    sym1struct.geoname = strtok(NULL, "+");

	    static char sym2text[80];
	    char *p = strrchr(sympart2[xkbsym2].id, '+');
	    strcpy(sym2text, sympart2[xkbsym2].id);
	    sym2struct.prefix = strtok(sym2text, "+");
	    sym2struct.extend = (char*)(p ? p : "");

	    /* XXX check consistency: currently en_US supports only pc101 and 102,
	     * which is IMHO wrong, because I have seen German MS-Keyboards at
	     * least (hv)
	     */
	    if (sym1struct.usonly && !streq(sym2struct.prefix, "us")) {
		char msg[2000];

		sprintf(msg, "You have chosen the combination:\n"
			     "         keyboard %s\n"
			     "         country %s\n"
			     "This configuration might be incompatible\n"
			     "and not supported yet.  Use it anyway?", 
		       sympart1[xkbsym1].item,
		       sympart2[xkbsym2].item);

		rc = dialog_yesno(TITLE, msg, -1, -1);

		if (rc != 0)
		    continue;
	    }
	    /* compose the lines */
	    disable = 0;
	    keymap = 0;
	#ifdef XFREE98_XKB
	    keycodes = "xfree98";	/* static */
	#else
	    keycodes = "xfree86";	/* static */
	#endif
	    types = "default";	/* static */
	    compat = "default";	/* static */

	    i = strlen(sym2struct.prefix)
		+ strlen(sym1struct.symname)
		+ strlen(sym2struct.extend)
		+ 4;
	    if (symbols)
		free(symbols);
	    symbols = (char*)malloc(i);
	    sprintf(symbols, "%s(%s)%s",
		    sym2struct.prefix,
		    sym1struct.symname,
		    sym2struct.extend);

	    if (geometry)
		free(geometry);
	    geometry = strdup(sym1struct.geoname);

	    done();
	    return 1;
	} /* while loop around `select country' */
    } /* while loop around `standard keyboards' */
} /* composekeymaps */


/*
 *  Add new standard keymaps here
 */
static ListItem keymaps[] = {
    { "xfree86(us)",	"Standard 101-key, US encoding", },
    { "xfree86(us_microsoft)", "Microsoft Natural, US encoding", },
    { "xfree86(us_flexpro)", "KeyTronic FlexPro, US encoding", },
    { "xfree86(en_US)",	"Standard 101-key, US encoding with ISO9995-3 extensions", },
    { "xfree86(de)",	"Standard 101-key, German encoding", },
    { "xfree86(fr)",	"Standard 101-key, French encoding", },
    { "xfree86(th)",	"Standard 101-key, Thai encoding", },
    { "xfree86(de_CH)",	"Standard 101-key, Swiss/German encoding", },
    { "xfree86(fr_CH)",	"Standard 101-key, Swiss/French encoding", },
#ifdef XFREE98_XKB
    { "xfree98(jp)",	"NEC PC98, Japanese encoding", },
#endif
    { "custom",		"None of the above", },
};

#define NKEYMAPS	((sizeof keymaps / sizeof keymaps[0]))

KeyBoard::KeyBoard()
{
    /* preset the config variables */
    blurb = 0;
    altmeta = disable = 0;
    keycodes = types = compat = symbols = geometry = 0;
    keymap = keymaps[0].id;	/* default to xfree86(us) keymap */
}


int
KeyBoard::configure(int stage2)
{
    int rc;

    while (1) {
	altmeta = disable = 0;
	if (!stage2) {
	    rc = dialog_yesno_extended(TITLE, 
    "Beginning with XFree86 3.1.2D, you can use the new X11R6.1 XKEYBOARD\n"
    "extension to manage the keyboard layout, instead of using the old method\n"
    "of adjusting your keyboard layout with xmodmap",
		    -1, -1, "Use XKB", "Use old method");


	    if (rc < 0)
		return 0;

	    if (rc > 0) {
		disable = 1;
		if (xmodmap_configuration())
		    return 1;
	    }
	}

	while (1) {
	    if (!stage2) {
		rc = Xmesg(TITLE,
#if defined(FORCE_XKB_DIALOG)
    "Beginning with XFree86 3.1.2D, the X server uses the new X11R6.1\n"
    "XKEYBOARD extension to manage the keyboard layout. This requires you to\n"
    "answer a number of questions to add certain entries to the " CONFIGNAME "\n"
    " file.\n"
#endif
    "The following dialogue will allow you to select from a list of already\n"
    "preconfigured keymaps. If you don't find a suitable keymap in the list,\n"
    "the program will try to combine a keymap from additional information you\n"
    "are asked then. Such a keymap is by default untested and may require\n"
    "manual tuning. Please report success or required changes for such a\n"
    "keymap to XFREE86@XFREE86.ORG for addition to the list of preconfigured\n"
    "keymaps in the future.");

		if (rc != 0)
#ifdef FORCE_XKB_DIALOG
		    return 0;
#else
		    break;
#endif
	    }

	    rc = Xmenu(TITLE, "Please choose a keymap",12,
			       keymaps, NKEYMAPS, 0, 0);

	    if (rc >= NKEYMAPS-1) {
		/* CUSTOM KEYMAP */
		if (composekeymaps())
		    return 1;
	    }
	    else if (rc >= 0) {
		keymap = keymaps[rc].id;
		done();
		return 1;
	    }
	}
    }
} /* configure */
