/*****************************************************************************/
/*  xsol.c - A solitare program for X Windows written using Motif            */
/*  Copyright (C) 1998 Brian Masney <masneyb@newwave.net>                    */
/*                                                                           */
/*  This program is free software; you can redistribute it and/or modify     */
/*  it under the terms of the GNU General Public License as published by     */
/*  the Free Software Foundation; either version 2 of the License, or        */
/*  (at your option) any later version.                                      */
/*                                                                           */
/*  This program is distributed in the hope that it will be useful,          */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
/*  GNU General Public License for more details.                             */
/*                                                                           */
/*  You should have received a copy of the GNU General Public License        */
/*  along with this program; if not, write to the Free Software              */
/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
/*****************************************************************************/

#include <Xm/Xm.h>
#include <Xm/CascadeB.h> 
#include <Xm/DrawingA.h>
#include <Xm/MainW.h>
#include <Xm/PushB.h>
#include <Xm/RowColumn.h>
#include <Xm/Label.h>
#include <Xm/MessageB.h>
#include <Xm/Form.h>
#include <Xm/ToggleB.h>
#include <Xm/Frame.h>
#include <Xm/Separator.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "xsol.h"  

#define CARD_WIDTH	70   /* Width of the card */
#define CARD_HEIGHT	85   /* Height of the card */
#define PILE_COL	10   /* Starting x coord for piles */
#define PILE_ROW	125  /* Starting y coord for bottom row */
#define DECK_ROW	10   /* Starting y coord for top row */
#define MOUSE_DCLK	300  /* Allowable time for mouse dbl-click */
#define VERSION		"0.31"

struct stck { /* This contains all of the information about a card */
   int xcoord, ycoord;
   Pixmap under, face; /* Under is what was underneath the card */
                       /* Face is the generated card face */
   char type[3]; /* Type of card, for example 2S = Two of Spades */
   int shown; /* Can we see it? */
   struct stck *next; /* Next card in stack (works it way from bottom up) */
   struct stck *prev; /* Prev card in stack (works it way from top down) */
};

struct undo_stk { /* Undo stack */
   int xcoord, ycoord, frompile, topile, shown, numcards, score;
   struct undo_stk *next;
};

struct stck *piles[13]; /* Pile information. Piles 0-6 are the bottom 7
			 * piles. Pile 7 is the deck of cards, 8 is the
			 * cards in the deck you can see and 9-12 are
			 * the final resting areas for the cards */

void UpScore(int num);
char CardOrder(char face);
int IsValidMove(int frompile, char fromcard[3], int topile, char tocard[3]);
void init_cards(void);
void exitCB(Widget widget, XtPointer client_data, XtPointer call_data);
void newCB(Widget widget, XtPointer client_data, XtPointer call_data);
void undoCB(Widget widget, XtPointer client_data, XtPointer call_data);
void aboutCB(Widget parent, XtPointer client_data, XtPointer call_data);
void optionsCB(Widget parent, XtPointer client_data, XtPointer call_data);
void buttonCB(Widget parent, XtPointer client_data, XtPointer call_data);
void DrawCards(Display* display, Window window, int width, int height);
void drawCB(Widget widget, XtPointer client_data, XtPointer call_data);
void mousepress(Widget widget, XtPointer client_data, XButtonEvent *event, Boolean *continue_to_dispatch);
void mouserel(Widget widget, XtPointer client_data, XButtonEvent *event, Boolean *continue_to_dispatch);
void mousedrag(Widget widget, XtPointer client_data, XButtonEvent *event, Boolean *continue_to_dispatch);
void timerCB(XtPointer client_data, XtIntervalId *timer_id);
void UpdStatusBar(void);
Widget CreateMenu(Widget parent, char* name);
Widget CreateMenuItem(Widget parent, char *name, XtCallbackProc callback, XtPointer client_data);

Widget drawa, /* Drawing area widget. Public so that I can call XtWindow and
	       * XtDisplay from inside the functions. Just easier to make it 
	       * this way. I know, bad coding...will fix it soon */
       score_widget, /* Score widget */
       undomenu, /* Undo Menu Item so that it can be activated/inactived; */
       drawone_wid, /* Options dialog, Draw one */
       drawthree_wid; /* Options dialog, Draw three */
XmString newscore;
GC gc; /* Graphics content */
Pixmap cardbk, face, under; /* cardbk is pic of a card not being shown
			     * face and under are used for when a card is
			     * being dragged with the mouse */
int drawone = 1, /* 1 = Draw One,  0 = Draw Three */
    istimer = 1, /* 1 = Timer On, 0 = Timer Off */
    isscore = 1, /* 1 = Keep Score, 0 = No Score */
    iscountcrd = 0; /* 1 = Count # of cards left in deck, 0 = Don't */
int pile_distance;
int inited = 0, /* Set to false if the drawCB function needs to grab the
	         * area under the cards */
   dragged = 0, /* Set to true if the mouse is moving a card */
   diffx = -1, diffy = -1, xcoord, ycoord, /* Used to detect double click of
					    * mouse */
   frompile, /* Set when dragged is true. Keeps track of the pile of where the 
	      * moved card is from */
   ydraglen, /* Used for multiple card moves. It will keep track of the y 
	      * distance to remember when moving them */
   score, /* This isn't the score ;) */
   deckturn, /* Number of times shuffled through the deck */
   numcards; /* Number of cards left in the deck */
Time dclk_time = (Time) 0; /* Number of times shuffled through the deck. Used
			    * only for scoring purposes */
unsigned long time_elapsed; /* Number of seconds elapsed */
struct stck *moved_card; /* Pointer to the currently top moved card */
struct undo_stk *undo; /* Stack containing data for undo */

int main(int argc, char **argv) {
   XtAppContext app_context;
   Widget parent, mainwindow, menubar, gamemenu;
   Display *display;
   Arg args[20];
   int n, i;
    
   for(i=1; i<argc; i++) {
      if(strcmp(argv[i], "-notimer") == 0) istimer = 0;
      else if(strcmp(argv[i], "-timer") == 0) istimer = 1;
      else if(strcmp(argv[i], "-noscore") == 0) isscore = 0;
      else if(strcmp(argv[i], "-score") == 0) isscore = 1;
      else if(strcmp(argv[i], "-nocountcrd") == 0) iscountcrd = 0;
      else if(strcmp(argv[i], "-countcrd") == 0) iscountcrd = 1;
      else if(strcmp(argv[i], "-drawone") == 0) drawone = 1;
      else if(strcmp(argv[i], "-drawthree") == 0) drawone = 0;
      else {
         if(strcmp(argv[i], "--help") != 0) printf("Error: Option %d is invalid: %s\n\n", i, argv[i]);
         printf("X Solitare version %s. Copyright (C) 1998 Brian Masney\n", VERSION);
         printf("X Solitare is free software and comes with ABSOLUTELY NO WARRANTY\n");
         printf("Please read the COPYING file for the license agreement\n\n");	          
         printf("Options available:\n");
         printf("\t-notimer\tDisables the timer%s\n", !istimer ? " (default)" : "");
         printf("\t-timer\t\tEnables the timer%s\n", istimer ? " (default)" : "");
         printf("\t-noscore\tDoes not keep track of the score%s\n", !isscore ? " (default)" : "");
         printf("\t-score\t\tKeeps track of the score%s\n", isscore ? " (default)" : "");
         printf("\t-nocountcrd\tDoes not tell you how many cards left in deck%s\n", !iscountcrd ? " (default)" : "");
         printf("\t-countcrd\tTells you how many cards are left in deck%s\n", iscountcrd ? " (default)" : "");
         printf("\t-drawone\tWill draw one card from the deck%s\n", drawone ? " (default)" : "");
         printf("\t-drawthree\twill draw three cards from the deck%s\n", !drawone ? " (default)" : "");
         exit(-1);
      }
   }
   n = 0;
   XtSetArg(args[n], XmNtitle, "X Solitare"); n++; 
   XtSetArg(args[n], XmNwidth, 690); n++;
   XtSetArg(args[n], XmNheight, 460); n++;
   parent = XtAppInitialize(&app_context, NULL, (XrmOptionDescList) NULL, 0,
                            &argc, argv, (String*) NULL, args, n);

   n = 0;
   mainwindow = XmCreateMainWindow(parent, NULL, args, n);

   n = 0;
   drawa = XmCreateDrawingArea(mainwindow, NULL, args, n);

   XtAddCallback(drawa, XmNexposeCallback, (XtCallbackProc) drawCB, (XtPointer) NULL);
   XtAddCallback(drawa, XmNinputCallback, (XtCallbackProc) drawCB, (XtPointer) NULL);
   XtAddCallback(drawa, XmNresizeCallback, (XtCallbackProc) drawCB, (XtPointer) NULL);

   XtAddEventHandler(drawa, ButtonPressMask, 0, (XtEventHandler) mousepress, (XtPointer) NULL);
   XtAddEventHandler(drawa, ButtonReleaseMask, 0, (XtEventHandler) mouserel, (XtPointer) NULL);
   XtAddEventHandler(drawa, Button1MotionMask, 0, (XtEventHandler) mousedrag, (XtPointer) NULL);
   XtManageChild(drawa);


   n = 0;
   menubar = XmCreateMenuBar(mainwindow, "menubar", args, n);
   XtManageChild(menubar);
   gamemenu = CreateMenu(menubar, "Game");
   CreateMenuItem(gamemenu, "New Game", (XtCallbackProc) newCB, (XtPointer) NULL);
   undomenu = CreateMenuItem(gamemenu, "Undo", (XtCallbackProc) undoCB, (XtPointer) NULL);
   CreateMenuItem(gamemenu, "Options", (XtCallbackProc) optionsCB, (XtPointer) parent);
   CreateMenuItem(gamemenu, "About", (XtCallbackProc) aboutCB, (XtPointer) parent);
   CreateMenuItem(gamemenu, "Exit", (XtCallbackProc) exitCB, (XtPointer) NULL);

   n = 0;
   XtSetArg(args[n], XmNalignment, XmALIGNMENT_END); n++;
   score_widget = XmCreateLabel(mainwindow, "", args, n);
   XtAppAddTimeOut(app_context, 1000, (XtTimerCallbackProc) timerCB, (XtPointer) app_context);
   XtManageChild(mainwindow);
   XtRealizeWidget(parent);

   display = XtDisplay(drawa);
   gc = XCreateGC(display , XtWindow(drawa), 0, (XGCValues *) NULL);
   init_cards();

   XmMainWindowSetAreas(mainwindow, menubar, (Widget) NULL, (Widget) NULL, 
       (Widget) NULL, drawa);
   XtVaSetValues(mainwindow, XmNmessageWindow, score_widget, NULL);
   XtManageChild(score_widget);
   XtAppMainLoop(app_context);
   return 0;
}
/*****************************************************************************/
void timerCB(XtPointer client_data, XtIntervalId *timer_id) {

/* This function gets called every second */

   time_elapsed++;
   if(istimer) UpdStatusBar();
   XtAppAddTimeOut((XtAppContext) client_data, 1000, (XtTimerCallbackProc) timerCB, client_data);
}
/*****************************************************************************/
void exitCB(Widget widget, XtPointer client_data, XtPointer call_data) {  

/* Menu callback for File, Exit */

   struct stck *temp;
   struct undo_stk *temp_undo;
   int i;
   
   for(i=0; i<13; i++) {
      while(piles[i] != NULL) {
         temp = piles[i];
         piles[i] = piles[i]->next;
         free(temp);
      }
   }
   while(undo != NULL) {
      temp_undo = undo;
      undo = undo->next;
      free(temp_undo);
   }
   exit(0);
}
/*****************************************************************************/
void aboutCB(Widget parent, XtPointer client_data, XtPointer call_data) {

/* The about dialog box */

   Widget info, label;
   XmString inf_lbl, push_lbl;
   Arg args[20];
   int n;
      
   n = 0;
   XtSetArg(args[n], XmNtitle, "About"); n++;
   XtSetArg(args[n], XmNdialogStyle, XmDIALOG_SYSTEM_MODAL); n++;
   info = XmCreateFormDialog(*(Widget *) client_data, NULL, args, n);
   inf_lbl = XmStringCreateLocalized("\nThis program was written by\n\nBrian Masney\nmasneyb@newwave.net\n\nPlease feel free to email me any comments,\nsuggestions, or bugs about this program.\n");
   label = XtVaCreateManagedWidget(NULL, xmLabelWidgetClass, info,
      XmNtopAttachment, XmATTACH_FORM,
      XmNtopOffset, 10, 
      XmNleftAttachment, XmATTACH_FORM,
      XmNleftOffset, 10, 
      XmNrightAttachment, XmATTACH_FORM,
      XmNrightOffset, 10, 
      XmNlabelString, inf_lbl,
      NULL);
   push_lbl = XmStringCreateLocalized("OK");
   XtVaCreateManagedWidget(NULL, xmPushButtonWidgetClass, info,  
      XmNlabelString, push_lbl,
      XmNtopAttachment, XmATTACH_WIDGET,
      XmNtopWidget, label,
      XmNbottomAttachment, XmATTACH_FORM, 
      XmNbottomOffset, 10, 
      XmNleftAttachment, XmATTACH_POSITION, 
      XmNleftPosition, 20, 
      XmNrightAttachment, XmATTACH_POSITION, 
      XmNrightPosition, 80,  
      NULL);
   XtManageChild(info);
}
/*****************************************************************************/
void optionsCB(Widget parent, XtPointer client_data, XtPointer call_data) {

/* The options dialog box. */

   Widget dialog, frame, rowcol, tim_ck, score_ck, num_ck, title, ok;
   Arg args[20];
   int n;
   
   n = 0;
   XtSetArg(args[n], XmNtitle, "Settings"); n++;
   XtSetArg(args[n], XmNdialogStyle, XmDIALOG_SYSTEM_MODAL); n++;
   dialog = XmCreateFormDialog(*(Widget *) client_data, NULL, args, n);
   frame = XtVaCreateManagedWidget("frame", xmFrameWidgetClass, dialog, 
      XmNtopAttachment, XmATTACH_FORM,
      XmNtopOffset, 5,
      XmNleftAttachment, XmATTACH_FORM,
      XmNleftOffset, 10,
      XmNrightAttachment, XmATTACH_FORM,
      XmNrightOffset, 10,
      NULL);
   title = XtVaCreateManagedWidget("Settings", xmLabelWidgetClass, frame, 
             XmNchildType, XmFRAME_TITLE_CHILD,
             XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
             XmNchildVerticalAlignment, XmALIGNMENT_BASELINE_BOTTOM, NULL);   

   rowcol = XtVaCreateManagedWidget("rowcol", xmRowColumnWidgetClass, frame, NULL);

   tim_ck = XtVaCreateManagedWidget("Timed Game", xmToggleButtonWidgetClass, rowcol, 
      XmNindicatorType, XmONE_OF_MANY, 
      XmNset, istimer, 
      NULL);
   XtAddCallback(tim_ck, XmNvalueChangedCallback, buttonCB, (XtPointer) 1);

   score_ck = XtVaCreateManagedWidget("Keep Score", xmToggleButtonWidgetClass, rowcol, 
      XmNindicatorType, XmONE_OF_MANY, 
      XmNset, isscore, 
      NULL);
   XtAddCallback(score_ck, XmNvalueChangedCallback, buttonCB, (XtPointer) 2);

   num_ck = XtVaCreateManagedWidget("Show number of cards in deck", xmToggleButtonWidgetClass, rowcol, 
      XmNindicatorType, XmONE_OF_MANY, 
      XmNset, iscountcrd, 
      NULL);
   XtAddCallback(num_ck, XmNvalueChangedCallback, buttonCB, (XtPointer) 3);

   XtVaCreateManagedWidget("separator", xmSeparatorWidgetClass, rowcol, NULL);

   drawone_wid = XtVaCreateManagedWidget("Draw One", xmToggleButtonWidgetClass, rowcol, 
      XmNindicatorType, XmONE_OF_MANY, 
      XmNset, drawone, 
      NULL);
   XtAddCallback(drawone_wid, XmNvalueChangedCallback, buttonCB, (XtPointer) 4);


   drawthree_wid = XtVaCreateManagedWidget("Draw Three", xmToggleButtonWidgetClass, rowcol, 
      XmNindicatorType, XmONE_OF_MANY, 
      XmNset, !drawone, 
      NULL);
   XtAddCallback(drawthree_wid, XmNvalueChangedCallback, buttonCB, (XtPointer) 5);

   ok = XtVaCreateManagedWidget("OK", xmPushButtonWidgetClass, dialog, 
      XmNtopAttachment, XmATTACH_WIDGET,
      XmNtopWidget, frame,
      XmNtopOffset, 10,
      XmNbottomAttachment, XmATTACH_FORM, 
      XmNbottomOffset, 10, 
      XmNleftAttachment, XmATTACH_POSITION, 
      XmNleftPosition, 20, 
      XmNrightAttachment, XmATTACH_POSITION, 
      XmNrightPosition, 80,  
      NULL);

   XtManageChild(dialog);
}
/*****************************************************************************/
void buttonCB(Widget parent, XtPointer client_data, XtPointer call_data) {

/* Callback for radio buttons in dialog box. Will set the options */
/* I need to modify this, make it neater */

   XmToggleButtonCallbackStruct * ptr;
   
   ptr = (XmToggleButtonCallbackStruct *) call_data;
   switch((int) client_data) {
      case 1 : istimer = ptr->set; break;
      case 2 : isscore = ptr->set; break;
      case 3 : iscountcrd = ptr->set; break;
      case 4 : if(!ptr->set) {
                  XtVaSetValues(drawone_wid, XmNset, drawone, NULL); 
                  break;
               }
               drawone = True; 
               XtVaSetValues(drawthree_wid, XmNset, !drawone, NULL); 
               XtVaSetValues(drawone_wid, XmNset, drawone, NULL); 
               break;
      case 5 : if(!ptr->set) {
                  XtVaSetValues(drawthree_wid, XmNset, !drawone, NULL);
                  break;
               }
               drawone = False; 
               XtVaSetValues(drawone_wid, XmNset, drawone, NULL);
               XtVaSetValues(drawthree_wid, XmNset, !drawone, NULL);
               break;
      case 6 : XtUnmanageChild(parent);
   }
   UpdStatusBar();
}
/*****************************************************************************/
void undoCB(Widget widget, XtPointer client_data, XtPointer call_data) {  

/* Menu callback for File, Undo */

   struct undo_stk *temp_undo;
   struct stck *temp;
   int i;
   Display *display;
   Window window;
      
   display = XtDisplay(drawa);
   window = XtWindow(drawa);
   if(undo == NULL) return;
   temp_undo = undo;
   temp = piles[temp_undo->topile];
   for(i=0; i<undo->numcards; i++) {
      XCopyArea(display, temp->under, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord);
      temp = temp->next;
   }                  
   temp = piles[temp_undo->topile];
   for(i=0; i<undo->numcards-1; i++) temp = temp->next;
   if(piles[temp_undo->topile] != NULL) piles[temp_undo->topile]->prev = NULL;
   if(piles[temp_undo->frompile] != NULL) piles[temp_undo->frompile]->prev = temp;
   piles[temp_undo->topile] = temp->next;
   for(i=0; i<undo->numcards; i++) {
      temp->xcoord = PILE_COL + (pile_distance*(temp_undo->frompile < 7 ? temp_undo->frompile : temp_undo->frompile < 9 ? temp_undo->frompile - 7 : temp_undo->frompile - 6));
      temp->ycoord = undo->ycoord + (temp_undo->frompile < 7 ? i*15 : 0);
      temp->shown = temp_undo->shown;
      XCopyArea(display, window, temp->under, gc, temp->xcoord, temp->ycoord, CARD_WIDTH, CARD_HEIGHT, 0, 0);
      if(temp->shown) XCopyArea(display, temp->face, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord);
      else XCopyArea(display, cardbk, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord);
      temp->next = piles[temp_undo->frompile];
      piles[temp_undo->frompile] = temp;
      temp = temp->prev;
      if(temp_undo->frompile == 7) numcards++;
      else if(temp_undo->topile == 7) numcards--;
   }
   if(temp_undo->score != 0) UpScore(temp_undo->score * -1);
   undo = undo->next;
   free(temp_undo);
   XtSetSensitive(undomenu, undo != NULL);
   UpdStatusBar();
}
/*****************************************************************************/
void newCB(Widget widget, XtPointer client_data, XtPointer call_data) {  

/* Menu callback for File, New, blah blah blah blah
 * Clears all the piles and undo stack */

   Display *display;
   Window window;
   struct stck *temp;
   struct undo_stk *temp_undo;
   int i;

   display = XtDisplay(drawa);
   window = XtWindow(drawa);   
   for(i=0; i<13; i++) {
      while(piles[i] != NULL) {
         temp = piles[i];
         XCopyArea(display, temp->under, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord);
         piles[i] = piles[i]->next;
         free(temp);
      }
   }
   while(undo != NULL) {
      temp_undo = undo;
      undo = undo->next;
      free(temp_undo);
   }
   init_cards();
   DrawCards(display, window, 0, 0);
}
/*****************************************************************************/
void DrawCards(Display *display, Window window, int width, int height) {

/* This function will draw the cards onto the screen */

   int i;
   struct stck *temp;

   for(i=0; i<13; i++) { 
      temp = piles[i];
      if(piles[i] == NULL && i != 7 && i != 8 && gc != NULL) 
         XDrawRectangle(XtDisplay(drawa), XtWindow(drawa), gc, i < 7 ? PILE_COL + (pile_distance*i) : PILE_COL + (pile_distance*(i-6)), i < 7 ? PILE_ROW : DECK_ROW, CARD_WIDTH-1, CARD_HEIGHT-1);
      while(temp != NULL && temp->next != NULL) temp = temp->next;
      while(temp != NULL) {
         if(!inited) XCopyArea(display, window, temp->under, gc, temp->xcoord, temp->ycoord, CARD_WIDTH, CARD_HEIGHT, 0, 0);
         if(temp->shown) XCopyArea(display, temp->face, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord);
         else XCopyArea(display, cardbk, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord);
         temp = temp->prev;
      }
   }
   inited = 1;
   XFlush(display);
}
/*****************************************************************************/
void drawCB(Widget widget, XtPointer client_data, XtPointer call_data) {

/* This function gets called when the window needs redrawn */

   XmDrawingAreaCallbackStruct* ptr;
   Dimension width, height;
   int i;
   struct stck *temp;
    
   ptr = (XmDrawingAreaCallbackStruct*) call_data;
   if(ptr->reason == XmCR_EXPOSE && ptr->event->xexpose.count == 0) {
      XtVaGetValues(widget, XmNwidth,  &width, XmNheight, &height, NULL);
      DrawCards(XtDisplay(widget), XtWindow(widget), (int) width, (int) height);
   }
   else if(ptr->reason == XmCR_RESIZE) {
      XtVaGetValues(widget, XmNwidth,  &width, XmNheight, &height, NULL);
      if(width >= (CARD_WIDTH * 7) + PILE_COL) pile_distance = ((width - PILE_COL - (CARD_WIDTH * 7)) / 7) + CARD_WIDTH;
      else pile_distance = CARD_WIDTH;
      for(i=0; i<13; i++) { 
         temp = piles[i];
         while(temp != NULL) {
            temp->xcoord = PILE_COL + (pile_distance*(i < 7 ? i : i < 9 ? i - 7 : i - 6));
            temp = temp->next;
         }
      }
      if(gc != NULL) {
         XClearWindow(XtDisplay(widget), XtWindow(widget));
         for(i=0; i<13; i++) {
            if(i != 7 && i != 8) 
               XDrawRectangle(XtDisplay(widget), XtWindow(widget), gc, i < 7 ? PILE_COL + (pile_distance*i) : PILE_COL + (pile_distance*(i-6)), i < 7 ? PILE_ROW : DECK_ROW, CARD_WIDTH-1, CARD_HEIGHT-1);
         }
      }
      DrawCards(XtDisplay(widget), XtWindow(widget), (int) width, (int) height);
   }
}
/*****************************************************************************/
void mousepress(Widget widget, XtPointer client_data, XButtonEvent *event, Boolean *continue_to_dispatch) {

/* This function gets called when the user clicks the mouse button. If the 
 * user clicks it on a card, then the dragged variable gets set so indicating
 * that we are moving a card. This function also handles turning over cards,
 * and shuffling through the deck of cards */

   Display *display;
   Window window;
   struct stck *temp;
   struct undo_stk *temp_undo;
   int i, done, depth;
   
   XtVaGetValues(drawa, XmNdepth, &depth, NULL);
   display = XtDisplay(drawa);
   window = XtWindow(drawa);
   frompile = -1;
   if(PILE_COL <= event->x && PILE_COL+CARD_WIDTH >= event->x && DECK_ROW <= event->y && DECK_ROW+CARD_HEIGHT >= event->y && !(piles[7] == NULL && piles[8] == NULL)) {
      temp_undo = malloc(sizeof(struct undo_stk));
      if(temp_undo == NULL) {
         printf("Failed to alloc memory\n");
         exitCB(NULL, NULL, NULL);
      }
      temp_undo->next = undo;
      undo = temp_undo;
      temp_undo->score = 0;
      if(piles[7] != NULL) {
         temp_undo->xcoord = PILE_COL + (pile_distance*7);
         temp_undo->ycoord = DECK_ROW;
         temp_undo->frompile = 7;
         temp_undo->topile = 8;
         temp_undo->shown = 0;
         temp_undo->numcards = 0;
         for(i=0; i<(drawone ? 1 : 3); i++) {
            temp = piles[7];
            if(piles[7] == NULL) break;
            temp_undo->numcards++;
            numcards--;
            XCopyArea(display, temp->under, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord); 
            piles[7] = piles[7]->next;
            if(piles[7] != NULL) piles[7]->prev = NULL;
            temp->next = piles[8];
            if(piles[8] != NULL) piles[8]->prev = temp;
            temp->xcoord += pile_distance + (30*i);
            temp->shown = 1;
            piles[8] = temp;      
            XCopyArea(display, window, temp->under, gc, temp->xcoord, temp->ycoord, CARD_WIDTH, CARD_HEIGHT, 0, 0); 
            XCopyArea(display, temp->face, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord);
         }
      }
      else {
         temp_undo->xcoord = PILE_COL + (pile_distance*8);
         temp_undo->ycoord = DECK_ROW;
         temp_undo->frompile = 8;
         temp_undo->topile = 7;
         temp_undo->shown = 1;
         temp_undo->numcards = 0;
         while(piles[8] != NULL) {
            numcards++;
            temp = piles[8];
            XCopyArea(display, temp->under, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord); 
            temp_undo->numcards++;
            piles[8] = piles[8]->next;
            if(piles[8] != NULL) piles[8]->prev = NULL;
            temp->next = piles[7];
            if(piles[7] != NULL) piles[7]->prev = temp;
            temp->xcoord = PILE_COL;
            temp->shown = 0;
            piles[7] = temp;      
            XCopyArea(display, window, temp->under, gc, temp->xcoord, temp->ycoord, CARD_WIDTH, CARD_HEIGHT, 0, 0); 
            XCopyArea(display, cardbk, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord);
         }
         deckturn++;
         if(drawone && deckturn > 1) {
            UpScore(-100);
            temp_undo->score = -100;
         }
         else if(!drawone && deckturn > 3) {
            UpScore(-20);
            temp_undo->score = -20;
         }
      }   
      UpdStatusBar();
   }
   for(i=8; i<13; i++) {
      if(piles[i] != NULL && piles[i]->xcoord <= event->x && piles[i]->xcoord+CARD_WIDTH >= event->x && piles[i]->ycoord <= event->y && piles[i]->ycoord+CARD_HEIGHT >= event->y) {
         moved_card = piles[i];
         dragged = 1;
         ydraglen = CARD_HEIGHT;
         diffx = event->x - moved_card->xcoord;
         diffy = event->y - moved_card->ycoord;
         xcoord = moved_card->xcoord;
         ycoord = moved_card->ycoord;    
         frompile = i;
         face = XCreatePixmap(display, window, CARD_WIDTH, CARD_HEIGHT, depth);
         under = XCreatePixmap(display, window, CARD_WIDTH, CARD_HEIGHT, depth);              
         XCopyArea(display, moved_card->face, face, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, 0, 0);
         XCopyArea(display, moved_card->under, under, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, 0, 0);
      }
   }   
   for(i=0; i<7; i++) {
      if(PILE_COL + (pile_distance*i) <= event->x && PILE_COL + (pile_distance*i) + CARD_WIDTH >= event->x) {
         temp = piles[i];
         while(temp != NULL) {
            if(temp->ycoord <= event->y && temp->ycoord + CARD_HEIGHT >= event->y) {
               if(temp->shown) {
                  dragged = 1;
                  diffx = event->x - temp->xcoord;
                  diffy = event->y - temp->ycoord;
                  xcoord = temp->xcoord;
                  ycoord = temp->ycoord;    
                  frompile = i;
                  moved_card = temp;
                  while(temp->prev != NULL) temp = temp->prev;
                  ydraglen = CARD_HEIGHT-15;
                  done = 0;
                  while(!done) {
                     if(strcmp(temp->type, moved_card->type) == 0) done = 1;
                     ydraglen += 15;
                     XCopyArea(display, temp->under, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord);
                     temp = temp->next;
                  }
                  face = XCreatePixmap(display, window, CARD_WIDTH, ydraglen, depth);
                  under = XCreatePixmap(display, window, CARD_WIDTH, ydraglen, depth);              
                  XCopyArea(display, window, under, gc, moved_card->xcoord, moved_card->ycoord, CARD_WIDTH, ydraglen, 0, 0);
                  temp = moved_card;
                  while(temp != NULL) {
                     XCopyArea(display, temp->face, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord);
                     temp = temp->prev;
                  }
                  XCopyArea(display, window, face, gc, moved_card->xcoord, moved_card->ycoord, CARD_WIDTH, ydraglen, 0, 0);
                  break;
               }
               else if(!strcmp(piles[i]->type, temp->type)) {
                  temp_undo = malloc(sizeof(struct undo_stk));
                  if(temp_undo == NULL) {
                     printf("Failed to alloc memory\n");
                     exitCB(NULL, NULL, NULL);
                  }
                  temp_undo->next = undo;
                  undo = temp_undo;
                  temp_undo->xcoord = temp->xcoord;
                  temp_undo->ycoord = temp->ycoord;
                  temp_undo->frompile = i;
                  temp_undo->topile = i;
                  temp_undo->shown = 0;
                  temp_undo->numcards = 1;
                  temp_undo->score = 5;
                  UpScore(5);
                  temp->shown = 1;
                  XCopyArea(display, temp->face, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord);
                  dragged = 0;
               }
            }
            temp = temp->next; 
         }
      }
   }
   XFlush(display);
}
/*****************************************************************************/
void mouserel(Widget widget, XtPointer client_data, XButtonEvent *event, Boolean *continue_to_dispatch) {

/* This function gets called when the user releases the mouse button. It will
 * handle moving the card to a separate pile if the user was dragging a card */

   struct stck *temp;
   struct undo_stk *temp_undo;
   int i, topile = -1, newy, yc;
   Display *display;
   Window window;

   display = XtDisplay(drawa);
   window = XtWindow(drawa);
   for(i=0; i<4; i++) {
      if( ( (PILE_COL + (pile_distance*(i+3)) <= event->x-diffx && PILE_COL + (pile_distance*(i+3)) + CARD_WIDTH >= event->x-diffx) ||
        (PILE_COL + (pile_distance*(i+3)) <= event->x-diffx+CARD_WIDTH && PILE_COL + (pile_distance*(i+3)) + CARD_WIDTH >= event->x-diffx+CARD_WIDTH)) &&
        ((DECK_ROW <= event->y-diffy && DECK_ROW + CARD_HEIGHT >= event->y-diffy) || (DECK_ROW <= event->y-diffy+CARD_HEIGHT && DECK_ROW + CARD_HEIGHT >= event->y-diffy+CARD_HEIGHT))) {
            if(event->x <= (PILE_COL + (pile_distance*(i+3)) + PILE_COL + (pile_distance*(i+4)) + CARD_WIDTH)/2) {
               topile = i+9;
               break;
            }        
            else topile = i+9;
      }
   }
   if(topile == -1) {
      for(i=0; i<7; i++) {
         yc = piles[i] == NULL ? PILE_ROW : piles[i]->ycoord;
         if(((PILE_COL + (pile_distance*i) <= event->x-diffx && PILE_COL + (pile_distance*i) + CARD_WIDTH >= event->x-diffx) ||
            (PILE_COL + (pile_distance*i) <= event->x-diffx+CARD_WIDTH && PILE_COL + (pile_distance*i) + CARD_WIDTH >= event->x-diffx+CARD_WIDTH)) &&
            ((yc <= event->y-diffy && yc + CARD_HEIGHT >= event->y-diffy) || (yc <= event->y-diffy+CARD_HEIGHT && yc + CARD_HEIGHT >= event->y-diffy+CARD_HEIGHT))) {
            if(event->x <= (PILE_COL + (pile_distance*i) + PILE_COL + (pile_distance*(i+1)) + CARD_WIDTH)/2) {
               topile = i;
               break;
            }        
            else topile = i;
         }
      }
   }
   if(dragged) {
      XCopyArea(display, under, window, gc, 0, 0, CARD_WIDTH, ydraglen, xcoord, ycoord);
      if((frompile == 8 ? 8 : topile) == frompile && event->time < (dclk_time + MOUSE_DCLK) && event->time > (dclk_time - MOUSE_DCLK)) {
         for(i=9; i<13; i++) {
            if(IsValidMove(frompile, moved_card->type, i, piles[i] == NULL ? "ZZ" : piles[i]->type)) {
               dclk_time = -1;
               topile = i;
               break;
            }
         }
      }
      else dclk_time = event->time;
   }  
   if(topile > 7 && dragged && frompile != -1 && strcmp(moved_card->type, piles[frompile]->type) == 0 && IsValidMove(frompile, moved_card->type, topile, piles[topile] == NULL ? "ZZ" : piles[topile]->type)) {
      temp_undo = malloc(sizeof(struct undo_stk));
      if(temp_undo == NULL) {
         printf("Failed to alloc memory\n");
         exitCB(NULL, NULL, NULL);
      }
      temp_undo->next = undo;
      undo = temp_undo;
      if(frompile < 9) {
         UpScore(10);
         temp_undo->score = 10;
      }
      else temp_undo->score = 0;
      temp = moved_card;
      temp_undo->xcoord = moved_card->xcoord;
      temp_undo->ycoord = moved_card->ycoord;
      temp_undo->frompile = frompile;
      temp_undo->topile = topile;
      temp_undo->shown = moved_card->shown;
      temp_undo->numcards = 1;
      piles[frompile] = piles[frompile]->next;
      if(piles[frompile] != NULL) piles[frompile]->prev = NULL;
      moved_card->next = piles[topile];
      moved_card->xcoord = PILE_COL + (pile_distance*(topile-6));
      moved_card->ycoord = DECK_ROW;
      XCopyArea(display, window, moved_card->under, gc, moved_card->xcoord, moved_card->ycoord, CARD_WIDTH, CARD_HEIGHT, 0, 0); 
      XCopyArea(display, moved_card->face, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, moved_card->xcoord, moved_card->ycoord);
      if(piles[topile] != NULL) piles[topile]->prev = moved_card;
      piles[topile] = moved_card;
   }
   if(topile != -1 && frompile != -1 && topile < 7 && frompile != topile && dragged && IsValidMove(frompile, moved_card->type, topile, piles[topile] == NULL ? "ZZ" : piles[topile]->type)) {
      temp = moved_card;
      temp_undo = malloc(sizeof(struct undo_stk));
      if(temp_undo == NULL) {
         printf("Failed to alloc memory\n");
         exitCB(NULL, NULL, NULL);
      }
      temp_undo->next = undo;
      temp_undo->xcoord = moved_card->xcoord;
      temp_undo->ycoord = moved_card->ycoord;
      temp_undo->frompile = frompile;
      temp_undo->topile = topile;
      temp_undo->shown = moved_card->shown;
      temp_undo->numcards = 0;
      undo = temp_undo;
      newy = piles[topile] == NULL ? PILE_ROW : piles[topile]->ycoord + 15;
      while(temp != NULL) {
         temp->xcoord = PILE_COL + (pile_distance*topile);
         temp->ycoord = newy;
         newy += 15;
         temp_undo->numcards++;
         XCopyArea(display, window, temp->under, gc, temp->xcoord, temp->ycoord, CARD_WIDTH, CARD_HEIGHT, 0, 0); 
         XCopyArea(display, temp->face, window, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, temp->xcoord, temp->ycoord);
         temp = temp->prev;
      }
      piles[frompile] = moved_card->next;;
      if(piles[frompile] != NULL) piles[frompile]->prev = NULL;
      moved_card->next = piles[topile];
      if(piles[topile] != NULL) piles[topile]->prev = moved_card;
      temp = moved_card;
      while(temp->prev != NULL) temp = temp->prev;
      piles[topile] = temp;
      if(frompile == 8) { 
         UpScore(5);
         temp_undo->score = 5;
      }
      else if(frompile > 8) {
         UpScore(-15);
         temp_undo->score = -15;
      }
      else temp_undo->score = 0;

   }      
   if(dragged) {
      XCopyArea(display, face, window, gc, 0, 0, CARD_WIDTH, ydraglen, moved_card->xcoord, moved_card->ycoord);
      XFreePixmap(display, face);
      XFreePixmap(display, under);
      dragged = 0;
   }
   XtSetSensitive(undomenu, undo != NULL);
   XFlush(display);
}
/*****************************************************************************/
void mousedrag(Widget widget, XtPointer client_data, XButtonEvent *event, Boolean *continue_to_dispatch) {

/* I really do need to do something with this function. This is the function
 * that gets called when the mouse is being dragged and if the mouse is on a
 * card, then it moves it */

   Display *display;
   Window window;
   int screen;

   display = XtDisplay(widget);
   window = XtWindow(widget);
   screen = DefaultScreen(display);
   if(dragged) {
      XCopyArea(display, under, window, gc, 0, 0, CARD_WIDTH, ydraglen, xcoord, ycoord);
      xcoord = event->x - diffx;
      ycoord = event->y - diffy;
      XCopyArea(display, window, under, gc, xcoord, ycoord, CARD_WIDTH, ydraglen, 0, 0); 
      XCopyArea(display, face, window, gc, 0, 0, CARD_WIDTH, ydraglen, xcoord, ycoord);
   }
   XFlush(display);
}
/*****************************************************************************/
Widget CreateMenu(Widget parent, char* name) {

/* Take a wild guess */

   Widget menu, cascade;
   Arg args[20];
   int n;

   n = 0;
   XtSetArg(args[n], XmNtearOffModel, XmTEAR_OFF_ENABLED); n++;
   menu = XmCreatePulldownMenu(parent, name, args, n);
   n = 0;
   XtSetArg(args[n], XmNsubMenuId, menu); n++;
   cascade = XmCreateCascadeButton(parent, name, args, n);
   XtManageChild(cascade);
   return menu;
}
/*****************************************************************************/
Widget CreateMenuItem(Widget parent, char *name, XtCallbackProc callback, XtPointer client_data) {

/* This is a tough one too */

   Widget push;
   
   push = XmCreatePushButton(parent, name, NULL, 0);
   XtAddCallback(push, XmNactivateCallback, callback, client_data);
   XtManageChild(push);
   return(push);
}
/*****************************************************************************/
void init_cards(void) {

/* Shuffles the cards, generates the card faces, and puts the cards in their
 * respective piles */

   Pixmap dummy;
   XColor xcolor;
   Colormap colormap;
   Dimension width;
   struct stck *temp;
   int i, j, newpos, num, fam, depth, status;
   char test[4];
   Display *display;
   Window window;
   char cards[52][3] = {"AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "TH", "JH", "QH", "KH",
                        "AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "TD", "JD", "QD", "KD",
                        "AS", "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "TS", "JS", "QS", "KS",
                        "AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "TC", "JC", "QC", "KC"};
   int card_pattern[7][8] = {{1,-1,-1,-1,-1,-1,-1,-1},
                             {0,1,-1,-1,-1,-1,-1,-1},
                             {0,0,1,-1,-1,-1,-1,-1},
                             {0,0,0,1,-1,-1,-1,-1},
                             {0,0,0,0,1,-1,-1,-1},
                             {0,0,0,0,0,1,-1,-1},
                             {0,0,0,0,0,0,1,-1}};

   inited = 0;
   score = 0;
   deckturn = 0;
   time_elapsed = 0;
   numcards = 52;
   undo = NULL;
   XtVaGetValues(drawa, XmNwidth,  &width, XmNdepth, &depth, NULL);
   if(width >= (CARD_WIDTH * 7) + PILE_COL) pile_distance = ((width - PILE_COL - (CARD_WIDTH * 7)) / 7) + CARD_WIDTH;
   else pile_distance = CARD_WIDTH;
   display = XtDisplay(drawa);
   window = XtWindow(drawa);
   colormap = DefaultColormap(display, DefaultScreen(display));
   xcolor.flags = DoRed | DoGreen | DoBlue;
   xcolor.red = 65535;
   xcolor.green = 0;
   xcolor.blue = 0;
   status = XAllocColor(display, colormap, &xcolor);
   XSetForeground(display, gc, BlackPixel(display, DefaultScreen(display)));
   XSetBackground(display, gc, WhitePixel(display, DefaultScreen(display)));
   for(i=0; i<13; i++) {
      piles[i] = NULL;
      if(i != 7 && i != 8) 
         XDrawRectangle(display, window, gc, i < 7 ? PILE_COL + (pile_distance*i) : PILE_COL + (pile_distance*(i-6)), i < 7 ? PILE_ROW : DECK_ROW, CARD_WIDTH-1, CARD_HEIGHT-1);
   }
   cardbk = XCreatePixmap(display, window, CARD_WIDTH, CARD_HEIGHT, depth);
   dummy = XCreateBitmapFromData(display, window, (char *)card_back, CARD_WIDTH, CARD_HEIGHT);
   XCopyPlane(display, dummy, cardbk , gc, 0, 0, CARD_WIDTH, CARD_HEIGHT, 0, 0, 0x01);

   srand(time(NULL));
   for(i=0; i<52; i++) {
      newpos = 1+(int) (51.0*rand()/(RAND_MAX+1.0));;
      strcpy(test,cards[i]);
      strcpy(cards[i],cards[newpos]);
      strcpy(cards[newpos],test);
   }
   for(i=0; i<52; i++) {
      if(!(temp = malloc(sizeof(struct stck)))) {
         printf("Failed to alloc memory\n");
         exitCB(NULL, NULL, NULL);
      }
      temp->xcoord = PILE_COL;
      temp->ycoord = DECK_ROW;
      temp->shown = 0;
      strcpy(temp->type, cards[i]);
      temp->face = XCreatePixmap(display, window, CARD_WIDTH, CARD_HEIGHT, depth);
      temp->under = XCreatePixmap(display, window, CARD_WIDTH, CARD_HEIGHT, depth);
      XSetForeground(display, gc, WhitePixel(display, DefaultScreen(display)));
      XFillRectangle(display, temp->face, gc, 0, 0, CARD_WIDTH, CARD_HEIGHT);
      XSetForeground(display, gc, BlackPixel(display, DefaultScreen(display)));
      XDrawRectangle(display, temp->face, gc, 0, 0, CARD_WIDTH-1, CARD_HEIGHT-1);
      if(temp->type[1] == 'S' || temp->type[1] == 'C') XSetForeground(display, gc, BlackPixel(display, DefaultScreen(display)));
      else XSetForeground(display, gc, xcolor.pixel);
      switch(temp->type[0]) {
         case 'T' : num = 9; break;
         case 'J' : num = 10; break;
         case 'Q' : num = 11; break;
         case 'K' : num = 12; break;
         case 'A' : num = 13; break;
         default :
            sprintf(test, "%c", temp->type[0]);
            num = atoi(test)-2;
            break;
      }
      switch(temp->type[1]) {
         case 'C' : fam = 0; break;
         case 'S' : fam = 1; break;
         case 'D' : fam = 2; break;
         case 'H' : fam = 3; break;
      }
      dummy = XCreateBitmapFromData(display, window, (char*)card_nums[num], 15, 15);
      XCopyPlane(display, dummy, temp->face , gc, 0, 0, 15, 15, 1, 1, 0x01);
      XCopyPlane(display, dummy, temp->face, gc, 0, 0, 15, 15, CARD_WIDTH-31, CARD_HEIGHT-16, 0x01);
      dummy = XCreateBitmapFromData(display, window, (char*)card_family[fam], 15, 15);
      XCopyPlane(display, dummy, temp->face, gc, 0, 0, 15, 15, 15, 1, 0x01);
      XCopyPlane(display, dummy, temp->face, gc, 0, 0, 15, 15, CARD_WIDTH-16, CARD_HEIGHT-16, 0x01);
      temp->next = piles[7];
      temp->prev = NULL;
      if(piles[7] != NULL) piles[7]->prev = temp;
      else temp->next = NULL;
      piles[7] = temp;
   }

   for(i=0; i<7; i++) {
      j=0;
      while(card_pattern[i][j] != -1) {
         numcards--;
         piles[7]->xcoord = PILE_COL + (pile_distance*i);
         piles[7]->ycoord = PILE_ROW + (15*j);
         temp = piles[7];
         piles[7] = piles[7]->next;
         piles[7]->prev = NULL;
         temp->next = piles[i];
         temp->prev = NULL;
         temp->shown = card_pattern[i][j];
         if(piles[i] != NULL) piles[i]->prev = temp;
         else temp->next = NULL;
         piles[i] = temp;
         j++;
      }
   }
   XSetForeground(display, gc, BlackPixel(display, DefaultScreen(display)));
   XtSetSensitive(undomenu, undo != NULL);
   UpdStatusBar();
}
/*****************************************************************************/
int IsValidMove(int frompile, char fromcard[3], int topile, char tocard[3]) {

/* Gets called after each move to see if it is valid
 * Note: 'Z' is my dummy NULL or empty pile */

   if(frompile == topile) return(0);
   if(topile > 8) {
      if(fromcard[0] == 'A' && tocard[0] == 'Z') return(1);
      else if(fromcard[1] == tocard[1]) {
         if(CardOrder(tocard[0]) == fromcard[0]) return(1);
         else return(0);
      }
      else return(0);
   }
   else {
      if(fromcard[0] == 'K' && tocard[0] == 'Z') return(1);
      if(CardOrder(fromcard[0]) == tocard[0]) {
         if( (fromcard[1] == 'S' || fromcard[1] == 'C') && (tocard[1] == 'H' || tocard[1] == 'D')) return(1);
         else if( (fromcard[1] == 'H' || fromcard[1] == 'D') && (tocard[1] == 'S' || tocard[1] == 'C')) return(1);
         else return(0);
      }
      else return(0);
   }
}
/*****************************************************************************/
char CardOrder(char face) {

/* What would the next card be? for example after 2, comes 3. After ten,
 * comes the jack, etc, etc, etc */

   if(face == 'Z') return('A');
   else if(face == 'A') return('2');
   else if(face >= '2' && face <= '8') return(face+1);
   else if(face == '9') return('T');
   else if(face == 'T') return('J');
   else if(face == 'J') return('Q');
   else if(face == 'Q') return('K');
   else return(-1); /* Shouldn't happen */
}
/*****************************************************************************/
void UpScore(int num) {

/* Increments the score and updates the display. I need to make a status bar
 * on the main window */

   score += num;
   UpdStatusBar();
}   
/*****************************************************************************/
void UpdStatusBar(void) {
   char temp[80] = "";
   char temp1[40];
   
   if(istimer) {
      sprintf(temp1, "Time: %ld ", time_elapsed);
      strcat(temp, temp1);
   }
   if(isscore) {
      sprintf(temp1, "Score: %d ", score);
      strcat(temp, temp1);
   }
   if(iscountcrd) {
      sprintf(temp1, "Cards In Deck: %d", numcards);
      strcat(temp, temp1);
   }
   newscore = XmStringCreateSimple(temp);
   XtVaSetValues(score_widget, XmNlabelString, newscore, NULL);
}
/*****************************************************************************/
