/*
 *      XCountdown - X version of the popular Channel 4 quiz show
 *
 * This software comes with NO warranty whatsoever. I therefore take no
 * responsibility for any damages, losses or problems caused through use
 * or misuse of this program.
 *
 * I hereby grant permission for this program to be freely copied and
 * distributed by any means, provided no charge is made for it.
 *
 * Matthew Chapman, csuoq@csv.warwick.ac.uk
 *    June 1995.
 */

/* menu.c - the Extras menu */

#include "xcountdown.h"
#include "globals.h"
#include "about.h"

#define dot_width 12
#define dot_height 12
static unsigned char dot_bits[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xf8, 0x01, 0xf8, 0x01,
    0xf8, 0x01, 0xf8, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
   
void ProcessMenu(Widget w, XtPointer client_data, XtPointer call_data);
void HelpPopup(int dnum);
void CreateHelpPopup(int dnum);
void HelpPopdown(Widget w, XtPointer client_data, XtPointer call_data);
void RulesPopup(int dnum);
void CreateRulesPopup(int dnum);
void RulesPopdown(Widget w, XtPointer client_data, XtPointer call_data);
void CancelQuit(Widget w, XtPointer client_data, XtPointer call_data);
void CreateConfirm(int dnum);

static Pixmap mark[NP];
static Boolean menu_status[NP][MENU_ITEMS];
static Widget menuButton[NP],menu[NP],menu_item[NP][MENU_ITEMS];
static Widget rtop[NP],rdismiss[NP];
static Widget htop[NP],hdismiss[NP];
char *progname = "XCountdown";

static String help_txt = "This text is about using XCountdown. For the rules of Countdown, select Rules from the Extras Menu.\n\nTo start the game, both players must type their names into the appropriate box in their window. The first player is on the left of the window, and the second on the right. Most of the user interaction takes place via these boxes.\n\nTo select letters the player whose turn it is simply clicks on the Vowel button or the Consonant button, as desired. This is repeated until all 9 letters have been selected. Players must type their answer into their box before the time runs out, although a few extra seconds are allowed. The input is then read from the boxes, displayed to the other player, validated and scored.\n\nIn the numbers round the player is presented with a grid of squares which represent a randomly ordered collection of numbers. 6 squares must then be selected by the player, by clicking on them with the pointer. Clicking on selected squares causes them to be deselected, although the process ends as soon as 6 squares have been selected. As with the letters round, answers must be entered during the time limit. At this stage only the total you have reached is required, not your method. You may then be required to enter your method. An extra window will popup for this. Simply enter your method as a single mathematical expression and press return. Brackets are allowed, and standard mathematical precedence rules are applied.\n\nFor the conundrum, you must enter your answer and then press return. The act of pressing return submits your answer, so this must be done within the time limit. You only get one attempt.\n\nAfter the game is finished, another can be played by selecting New Game from the Extras Menu. If this item is selected during a game, nothing will happen until the end of the game, at which point a new game will be started straightaway. It need only be selected by one player to have effect. The Quit option should be used to end the game.\n\n";

static String rules_txt = "The Letters Round.\n------------------\n\nFor this round there are two piles of letters: one with all the vowels, and one with all the consonants. These piles are mixed up at the start of the game. The number of copies of each letter is based approximately on the frequency which it occurs in the English language. Each round is controlled by one of the players, usually alternating between the two players. The designated player chooses either a vowel or a consonant. A letter is then taken from the appropriate pile and displayed on the board. This process is repeated until 9 letters have been chosen. The clock is then started, which counts down for 30 seconds - only half the clock face is used.\n\nThe object is to come up with a valid English word using only the letters available on the board. Each letter present may only be used once. The object is to make your word as long as possible.\n\nThe round is scored as follows: If a player has used a letter which is not available, or has used a given letter more than once, or whose word is not a correct English word, they score no points. If only one player has a valid word, they receive a point for each letter in their word, i.e. the length of their word. If both players have a valid word, a player with a longer word than the other player scores the length of that word, and the other player scores no points. If both players have a valid word of the same length, they both score the length of their words. The one exception to this is words which use all 9 letters - these receive a special score of 18 points.\n\n\nThe Numbers Round.\n------------------\n\nA grid of cards 6 columns by 5 rows is presented to the designated player. There are two cards missing from the top row, and one from the next row. The player has to chose any six of the available cards. The reverse of each card contains a number. The cards on the top row contain the numbers 100, 75, 50, and 25 in a random order. The remaining cards consist of two copies of every number from 1 to 10, in a random order. The six selected cards are displayed on a board. Then a random number in the range 101 to 999 is generated, known as the target number. The clock then counts down for 30 seconds.\n\nThe object of the game is to formulate a mathematical expression which evaluates to the target number, or as close to it as possible, subject to the following restrictions.\n\nThe only numbers which can be used are the ones displayed on the board. Each available number can only be used once. The only operators which can be used are addition (+), subtraction (-), multiplication (*), and division (/). When the allotted time has run out, both players declare the closest number they have reached, if this is within 10 of the target number, else they must pass. The player getting the closest, or the player who chose the numbers if equally close, must then demonstrate their method, so that it can be verified. If it is not valid, or if both players were equally close to the target number, then the other player tries their method.\n\nThe round is scored as follows. A player passing, or having an invalid method, or being beaten by a valid, closer expression from the other player, scores no points. A player with a valid method, which is the closest, or joint closest to the target number, scores depending on how close to the target number they were. They score 10 points for reaching the target number exactly, or 7 points for being within 5 of the target number, or 5 points for being with 10.\n\n\nThe Conundrum.\n--------------\nA 9 letter word is jumbled up, often in such a way as to contain smaller English words. The jumbled letters are revealed to the players, and then the clock is started. The object is to deduce what the original word is. A player may buzz in and guess the word. The first to guess the word correctly wins the round, scoring 10 points. Each player is only allowed one guess. If no-one has guessed correctly at the end of the round, the word is revealed, and no points are scored. The conundrum should be chosen so that its component letters cannot be rearranged into a different 9 letter English word.\n\n";


void SetupMenu(Widget top, Widget title, int dnum)
{
    char entry[8];
    int i;
    String mlabels[] = { "New Game","Help","Rules","About","Quit" };

    mark[dnum] = XCreateBitmapFromData(XtDisplay(top),
				       RootWindowOfScreen(XtScreen(top)),
				       (char *)dot_bits,dot_width,dot_height);

    menuButton[dnum] = XtVaCreateManagedWidget("menuButton",
					       menuButtonWidgetClass,top,
					       XtNlabel," Extras",
					       XtNfromHoriz,title,
					       NULL);
    menu[dnum] = XtVaCreatePopupShell("menu",
				      simpleMenuWidgetClass,
				      menuButton[dnum],
				      NULL);
    for (i=0; i<MENU_ITEMS; i++)
    {
	menu_status[dnum][i]=False;
	sprintf(entry,"entry%d",i);
	menu_item[dnum][i] = XtVaCreateManagedWidget(entry,
						     smeBSBObjectClass,
						     menu[dnum],
						     XtNlabel,mlabels[i],
						     XtNleftMargin,14,
						     NULL);
	XtAddCallback(menu_item[dnum][i],XtNcallback,ProcessMenu,top);
    }
}



void ProcessMenu(Widget w, XtPointer client_data, XtPointer call_data)
{
    char *name = XtName(w);
    int sel = name[5] - '0';
    int i,dnum=0;
	
    for (i=0; i<NP; i++)
	if (w==menu_item[i][sel])
	    dnum=i;

    if (menu_status[dnum][sel]==False)
	XtVaSetValues(w,XtNleftBitmap,mark[dnum],NULL);
    else
	XtVaSetValues(w,XtNleftBitmap,None,NULL);
    menu_status[dnum][sel]=!menu_status[dnum][sel];
    switch (sel)
    {
    case NEWGAME: new_game=menu_status[dnum][sel];
	break;
    case HELP: HelpPopup(dnum);
	break;
    case RULES: RulesPopup(dnum);
	break;
    case ABOUT: AboutPopup(dnum);
	break;
    case QUIT: ConfirmQuit(dnum); break;
    default: break;
    }
}

void ClearNewGame(int dnum)
{
    XtVaSetValues(menu_item[dnum][NEWGAME],XtNleftBitmap,None,NULL);
    menu_status[dnum][NEWGAME]=False;
    new_game=False;
}

void AboutDown(Widget w)
{
    int dnum;
	
    for (dnum=0;topl[dnum]!=w; dnum++)
	;

    XtVaSetValues(menu_item[dnum][ABOUT],XtNleftBitmap,None,NULL);
    menu_status[dnum][ABOUT]=False;
}

void HelpPopup(int dnum)
{
    if (!htop[dnum])
	CreateHelpPopup(dnum);
    if (menu_status[dnum][HELP]==False)
	/* popup is already up */
	XtUnmapWidget(htop[dnum]);
    else
	XtMapWidget(htop[dnum]);
}


void CreateHelpPopup(int dnum)
{
    Widget rform,rmain,rtitle,rview;
    const int WD=560,HT=407;
		
    htop[dnum] = XtVaAppCreateShell("htop","XCountdown",
				    applicationShellWidgetClass,dpy[dnum],
				    XtNmappedWhenManaged,False,
				    XtNtitle,"Help",
				    XtNiconName,"XCountdown",
				    XtNwidth,WD,
				    XtNminWidth,WD,
				    XtNmaxWidth,WD,
				    XtNheight,HT,
				    XtNminHeight,HT,
				    XtNmaxHeight,HT,
				    XtNcolormap,pseudo_cmap[dnum],
				    NULL);
    rform = XtVaCreateManagedWidget("rform",
				    formWidgetClass,htop[dnum],
				    NULL);
    rtitle = XtVaCreateManagedWidget("rtitle",
				     labelWidgetClass,rform,
				     XtNlabel,"Help on XCountdown",
				     XtNborderWidth,0,
				     NULL);
    rview = XtVaCreateManagedWidget("rview",
				    viewportWidgetClass,rform,
				    XtNfromVert,rtitle,
				    XtNwidth,550,
				    XtNheight,341,
				    XtNallowHoriz,False,
				    XtNallowVert,True,
				    XtNuseRight,True,
				    NULL);
    rmain = XtVaCreateManagedWidget("rmain",
				    asciiTextWidgetClass,rview,
				    XtNstring,help_txt,
				    XtNheight,500,
				    XtNwrap,XawtextWrapWord,
				    XtNscrollHorizontal,XawtextScrollNever,
				    XtNeditType,XawtextRead,
				    XtNscrollVertical,XawtextScrollNever,
				    NULL);
    XawTextDisplayCaret(rmain,False);
	
    hdismiss[dnum] = XtVaCreateManagedWidget("hdismiss",
					     commandWidgetClass,rform,
					     XtNfromVert,rview,
					     XtNlabel,"Dismiss",
					     NULL);
    XtRealizeWidget(htop[dnum]);
    XtAddCallback(hdismiss[dnum],XtNcallback,HelpPopdown,htop[dnum]);
}

void HelpPopdown(Widget w, XtPointer client_data, XtPointer call_data)
{
    int dnum;
	
    for (dnum=0;hdismiss[dnum]!=w; dnum++)
	;
    XtUnmapWidget(htop[dnum]);

    XtVaSetValues(menu_item[dnum][HELP],XtNleftBitmap,None,NULL);
    menu_status[dnum][HELP]= !menu_status[dnum][HELP];
}

void RulesPopup(int dnum)
{
    if (!rtop[dnum])
	CreateRulesPopup(dnum);
    if (menu_status[dnum][RULES]==False)
	/* popup is already up */
	XtUnmapWidget(rtop[dnum]);
    else
	XtMapWidget(rtop[dnum]);
}


void CreateRulesPopup(int dnum)
{
    Widget rform,rmain,rtitle,rview;
    const int WD=560,HT=407;
		
    rtop[dnum] = XtVaAppCreateShell("rtop","XCountdown",
				    applicationShellWidgetClass,dpy[dnum],
				    XtNmappedWhenManaged,False,
				    XtNtitle,"Rules",
				    XtNiconName,"XCountdown",
				    XtNwidth,WD,
				    XtNminWidth,WD,
				    XtNmaxWidth,WD,
				    XtNheight,HT,
				    XtNminHeight,HT,
				    XtNmaxHeight,HT,
				    XtNcolormap,pseudo_cmap[dnum],
				    NULL);
    rform = XtVaCreateManagedWidget("rform",
				    formWidgetClass,rtop[dnum],
				    NULL);
    rtitle = XtVaCreateManagedWidget("rtitle",
				     labelWidgetClass,rform,
				     XtNlabel,"The Rules of Countdown",
				     XtNborderWidth,0,
				     NULL);
    rview = XtVaCreateManagedWidget("rview",
				    viewportWidgetClass,rform,
				    XtNfromVert,rtitle,
				    XtNwidth,550,
				    XtNheight,341,
				    XtNallowHoriz,False,
				    XtNallowVert,True,
				    XtNuseRight,True,
				    NULL);
    rmain = XtVaCreateManagedWidget("rmain",
				    asciiTextWidgetClass,rview,
				    XtNstring,rules_txt,
				    XtNheight,1050,
				    XtNwrap,XawtextWrapWord,
				    XtNscrollHorizontal,XawtextScrollNever,
				    XtNeditType,XawtextRead,
				    XtNscrollVertical,XawtextScrollNever,
				    NULL);
    XawTextDisplayCaret(rmain,False);
	
    rdismiss[dnum] = XtVaCreateManagedWidget("rdismiss",
					     commandWidgetClass,rform,
					     XtNfromVert,rview,
					     XtNlabel,"Dismiss",
					     NULL);
    XtRealizeWidget(rtop[dnum]);
    XtAddCallback(rdismiss[dnum],XtNcallback,RulesPopdown,rtop[dnum]);
}

void RulesPopdown(Widget w, XtPointer client_data, XtPointer call_data)
{
    int dnum;
	
    for (dnum=0;rdismiss[dnum]!=w; dnum++)
	;
    XtUnmapWidget(rtop[dnum]);

    XtVaSetValues(menu_item[dnum][RULES],XtNleftBitmap,None,NULL);
    menu_status[dnum][RULES]= !menu_status[dnum][RULES];
}

void ConfirmQuit(int dnum)
{
    Window junk1;
    int int_x=200,int_y=200,junk2;
    unsigned int junk3;
    Position x,y;
    const int WIDTH = 150;
    const int HEIGHT = 62;

    if (!ctop[dnum])
	CreateConfirm(dnum);

    XQueryPointer(XtDisplay(topl[dnum]),
		  DefaultRootWindow(XtDisplay(topl[dnum])),
		  &junk1,&junk1,&int_x,&int_y,&junk2,&junk2,&junk3);
    x=(Position)int_x - 110;
    y=(Position)int_y - 78;
    fit_on_screen(topl[dnum],&x,&y,WIDTH,HEIGHT,30,50);
    XtVaSetValues(ctop[dnum],
		  XtNx,x,
		  XtNy,y,
		  XtNwidth,WIDTH,
		  XtNheight,HEIGHT,
		  XtNmaxWidth,WIDTH,
		  XtNminWidth,WIDTH,
		  XtNmaxHeight,HEIGHT,
		  XtNminHeight,HEIGHT,
		  NULL);
    XtPopup(ctop[dnum],XtGrabNonexclusive);

}

void CreateConfirm(int dnum)
{
    Widget cform,ctitle;

    ctop[dnum] = XtVaCreatePopupShell("ctop",
				      transientShellWidgetClass,topl[dnum],
				      XtNtitle,"XCountdown",
				      NULL);
    cform = XtVaCreateManagedWidget("cform",
				    formWidgetClass,ctop[dnum],
				    NULL);
    ctitle = XtVaCreateManagedWidget("ctitle",
				     labelWidgetClass,cform,
				     XtNlabel,"Really Quit?",
				     XtNborderWidth,0,
				     NULL);
    cquit[dnum] = XtVaCreateManagedWidget("cquit",
					  commandWidgetClass,cform,
					  XtNlabel,"Quit",
					  XtNfromVert,ctitle,
					  NULL);
    ccancel[dnum] = XtVaCreateManagedWidget("ccancel",
					    commandWidgetClass,cform,
					    XtNlabel,"Cancel",
					    XtNfromVert,ctitle,
					    XtNfromHoriz,cquit[dnum],
					    NULL);
    XtAddCallback(cquit[dnum],XtNcallback,FinalQuit,NULL);
    XtAddCallback(ccancel[dnum],XtNcallback,CancelQuit,NULL);
}

void CancelQuit(Widget w, XtPointer client_data, XtPointer call_data)
{
    int dnum;
	
    for (dnum=0; ccancel[dnum]!=w; dnum++)
	;
    XtPopdown(ctop[dnum]);
    XtVaSetValues(menu_item[dnum][QUIT],XtNleftBitmap,None,NULL);
    menu_status[dnum][QUIT]= !menu_status[dnum][QUIT];
}
