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

/* xnumround.c - interface routines for the numbers round */

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

void Go(void);

#define MYMETH "My method:\n"

void Score(void);
void LettToNum(Boolean forwards);

static int nums_sel=0,targ;
static Boolean has_ans,valid;
static int chosen[6],n_targ[NP],curr_ply;
static char sol[1024];
static String exp;

/* main interface to numbers game */
void NumRound(void)
{
    char buff[1024];

    in_conundrum=False;
    LettToNum(True);
    InitRound();
    sprintf(buff,"And now for round %d, a numbers round.",
	    round+1);
    DoMess(buff,3000);
    sprintf(buff,"Calling the numbers is %s. Select 6 numbers...",
	    app_data.name[ply_go]);
    DoMess(buff,1000);
    doing_nums=True;
    while (doing_nums)
	ProcessEvent();					
    round++;
    ply_go=1-ply_go;
    DoMess(" ",1000);
    LettToNum(False);
    InitRound();
}

/* starts round when 6 numbers have been selected (called from Tog) */
void Go(void)
{
    int i,count=0;
    char buff[1024];
    Boolean state;
    int ac,dn;
    int bulk[20],toprow[4],bcount=0,tcount=0;

    /* put numbers in */
    for (i=0; i<10; i++)
	bulk[i*2]=bulk[i*2+1]=i+1;
    for (i=0; i<4; i++)
	toprow[i]=(i+1)*25;

    /* shuffle numbers */
    for (i=0; i<1000;i++)
	Swap(&bulk[rand()%20],&bulk[rand()%20]);
    for (i=0; i<100;i++)
	Swap(&toprow[rand()%4],&toprow[rand()%4]);		
		
    for(dn=0; dn<4; dn++)
	for (ac=0; ac<7; ac++)
	{
	    if ((dn==0) && (ac==0 || ac==6))
		state=False;
	    else
		XtVaGetValues(num[0][ac][dn],XtNstate,&state,NULL);
	    if (state)
	    {
		if (dn==0)
		    chosen[count++]=toprow[tcount++];
		else
		    chosen[count++]=bulk[bcount++];
	    }
	}

    DoMess("The numbers are...",2000);			
    for (ac=0; ac<6; ac++)
    {
	Wait(1500);
	sprintf(buff,"%d",chosen[5-ac]);
	for (i=0; i<NP; i++)
	    XtVaSetValues(cnum[i][5-ac],XtNlabel,buff,SETBG(steelblue),NULL);
    }
    DoMess("And the number to get to is...",6000);

    /* select a number */
    for (i=0; i<50; i++)
    {
	targ=rand()%899+101;
	XcLcdUpdateValue(cecil[0],&targ);
	XcLcdUpdateValue(cecil[1],&targ);
	Wait(70);
    }
    ChangeCarol(1);
    DoMess("Enter the closest number you get to below...",3000);
    XtAppAddTimeOut(app_context,CLOCK_DELAY,Click,NULL);
    strcpy(sol,MYMETH);

#ifdef DEBUG
    for (i=0; i<6; i++)
	printf("chosen[%d]=%d\n",i,chosen[i]);
#endif
    /* do computer search */
    Carol(chosen,targ,sol);
    while (comp < 5000)
	ProcessEvent();
    DoMess("Right, time's up. Let's see how you did.",3000);
    ChangeCarol(2);
    WaitForMess();
    Score();
}

/* callback for squares on number round board */
void Tog(Widget w, XtPointer client_data, XtPointer call_data)
{
    int dnum = (XtDisplay(w)==dpy[0]) ? 0 : 1;
    int ac,dn,x=0,y=0;
    Boolean curr_state;

    /* must be right player, and currently have < 6 selected */
    XtVaGetValues(w,XtNstate,&curr_state,NULL);
    if ((dnum==ply_go) && (nums_sel<6))
    {
	for (dn=0; dn<4; dn++)
	    for (ac=0; ac<7; ac++)	
		if (w==num[dnum][ac][dn])
		{
		    x=ac;
		    y=dn;
		}
	XtVaSetValues(num[1-dnum][x][y],XtNstate,curr_state,NULL);
	if (curr_state)
	    nums_sel++;
	else
	    nums_sel--;

	if (nums_sel==6)
	    Go();
    }
    else
	/* selection invalid, so put toggle back */
	XtVaSetValues(w,XtNstate,!curr_state,NULL);
}

/* get player input for target and expression */
void Score(void)
{
    char s_targ[NP][5],buff[1024];
    String ans;
    int i,dist[NP],a,ac,dn;
    Boolean got_best=False,someone_has_done_it=False;

    for (i=0; i<NP; i++)
    {
	XawTextBlock txt;

	XtVaGetValues((i==0) ? input1[i] : input2[i],XtNstring,&ans,NULL);
#ifdef DEBUG
	printf("ans=%s.\n",ans);
#endif
	strncpy(s_targ[i],ans,4);
	n_targ[i]=atoi(s_targ[i]);
	dist[i]=abs(n_targ[i]-targ);
#ifdef DEBUG
	printf("s_targ=%s\n",s_targ[i]);
	printf("n_targ=%d, dist=%d\n",n_targ[i],dist[i]);
#endif
	txt.firstPos=0;
	txt.format=FMT8BIT;
	txt.length=strlen(s_targ[i]);
	txt.ptr=s_targ[i];
	XawTextReplace((i==0) ? input1[1-i] : input2[1-i],0,NL,&txt);

	if (dist[i]>10)
	{
	    sprintf(buff,"Never mind %s.",app_data.name[i]);
	    DoMess(buff,3000);		
	}		
    }
    if (dist[0]==dist[1])
	a=ply_go;
    else if (dist[0]<dist[1])
	a=0;
    else
	a=1;
    for (i=0; i<NP ;i++)
    {
	if ((dist[a]<=10) && (!got_best || dist[0]==dist[1]))
	{
	    XawTextBlock txt;
	    char empty='\0';

	    /* clear input popup */
	    txt.firstPos=0;
	    txt.format=FMT8BIT;
	    txt.length=0;
	    txt.ptr=&empty;
	    XawTextReplace(pmain[a],0,20,&txt);

	    sprintf(buff,"Enter your expression %s...",app_data.name[a]);
	    DoMess(buff,3000);
	    curr_ply=a;
	    has_ans=False;
	    XtMapWidget(ptop[a]);
	    /* wait for return to be pressed in input popup, and answer
	       evaluated
	       */
	    while (!has_ans)
		ProcessEvent();
	    curr_ply=-1;
	    if (valid)
	    {
		/* give player some points */
		int points;
				
		if (dist[a]==0)
		{
		    points=10;
		    someone_has_done_it=True;
		}
		else if (dist[a]<=5)
		    points=7;
		else
		    points=5;
		sprintf(buff,"Well done. %s scores %d points with %s.",app_data.name[a],
			points,exp);
		DoMess(buff,8000);
		WaitForMess();
		UpdateScore(a,points);
		got_best=True;
	    }
	    else
		DoMess("Sorry, no points.",3000);
	}
	a=1-a;	
    }
    WaitForMess();
    if (!strcmp(sol,MYMETH))
    {
	ChangeCarol(3);
	DoMess("There is no solution.",5000);
	Wait(5000);
	ChangeCarol(2);
    }
    else if (someone_has_done_it==False)
    {
	/* engage smug mode */
	ChangeCarol(3);
	DoMess("Here is my method:",3000);
	for (a=0; a<NP; a++)
	{
	    XtVaSetValues(smmain[a],XtNlabel,sol,NULL);
	    XtMapWidget(smtop[a]);
	}
	Wait(20000);
	ChangeCarol(2);
    }

    /* remove popups and reset board */
    for (a=0; a<NP; a++)
    {
	XtUnmapWidget(ptop[a]);
	XtUnmapWidget(smtop[a]);
    }
    for (a=0; a<NP; a++)
    {
	for(dn=0; dn<4; dn++)
	    for (ac=0; ac<7; ac++)
		if (!((dn==0) && (ac==0 || ac==6)))
		    XtVaSetValues(num[a][ac][dn],XtNstate,False,NULL);
	for (ac=0; ac<6; ac++)
	    XtVaSetValues(cnum[a][ac],XtNlabel,"   ",SETBG(gray90),NULL);
	XtVaSetValues(cecil[a],XtNvalue,0,NULL);
    }
    nums_sel=0;

    /* signal end of numbers round */
    doing_nums=False;
}

/* action proc for pressing return in input popup */
void Enter(Widget w, XtPointer client_data, XtPointer call_data)
{
    int dnum = (w==pmain[0]) ? 0 : 1;
	
    if (curr_ply==dnum)
    {
	XtVaGetValues(pmain[dnum],XtNstring,&exp,NULL);
#ifdef DEBUG
	printf("exp=%s.\n",exp);
#endif
	/* validate and verify player input */
	valid=CheckEntry(exp,chosen,n_targ[dnum]);
	has_ans=True;
    }
}

/* switch display from letters game to numbers, or vice versa */
void LettToNum(Boolean forwards)
{
    int i,ac,dn;

    /* unmap one lot and map the other */
    for (i=0; i<NP; i++)
    {
	for (dn=0; dn<2; dn++)
	    for (ac=0; ac<NL; ac++)
		XtVaSetValues(lett[i][ac][dn],XtNmappedWhenManaged,!forwards,NULL);
	XtVaSetValues(vbutt[i],XtNmappedWhenManaged,!forwards,NULL);
	XtVaSetValues(cbutt[i],XtNmappedWhenManaged,!forwards,NULL);

	for (ac=0; ac<6; ac++)
	    XtVaSetValues(cnum[i][ac],XtNmappedWhenManaged,forwards,NULL);
	for (dn=0; dn<4; dn++)
	    for (ac=0; ac<7; ac++)
		XtVaSetValues(num[i][ac][dn],XtNmappedWhenManaged,forwards,NULL);
	XtVaSetValues(cecil[i],XtNmappedWhenManaged,forwards,NULL);
    }
}
