From 4c523b628cd4038f959a444d5390d4394f862c6f Mon Sep 17 00:00:00 2001
From: ehouse <ehouse@0782aaa5-4710-0410-8820-a96bf9123855>
Date: Fri, 10 Jul 2009 05:04:04 +0000
Subject: [PATCH] Make slow-robot work for curses client too.

---
 xwords4/linux/cursesmain.c | 68 ++++++++++++++++++++++++++++++++------
 xwords4/linux/gtkmain.c    |  4 +--
 xwords4/linux/linuxmain.c  |  7 ++--
 xwords4/linux/main.h       |  9 +++--
 4 files changed, 70 insertions(+), 18 deletions(-)

diff --git a/xwords4/linux/cursesmain.c b/xwords4/linux/cursesmain.c
index f6bc613af..2fd110ddf 100644
--- a/xwords4/linux/cursesmain.c
+++ b/xwords4/linux/cursesmain.c
@@ -365,10 +365,16 @@ curses_util_setTimer( XW_UtilCtxt* uc, XWTimerReason why, XP_U16 when,
                       XWTimerProc proc, void* closure )
 {
     CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
+    XP_U32 nextTimer;
 
-    globals->cGlobals.timerProcs[why] = proc;
-    globals->cGlobals.timerClosures[why] = closure;
-    globals->nextTimer = util_getCurSeconds(uc) + when;
+    globals->cGlobals.timerInfo[why].proc = proc;
+    globals->cGlobals.timerInfo[why].closure = closure;
+
+    nextTimer = util_getCurSeconds(uc) + when;
+    globals->cGlobals.timerInfo[why].when = nextTimer;
+    if ( globals->nextTimer > nextTimer ) {
+        globals->nextTimer = nextTimer;
+    }
 } /* curses_util_setTimer */
 
 static void
@@ -899,13 +905,24 @@ static int
 figureTimeout( CursesAppGlobals* globals )
 {
     int result = INFINITE_TIMEOUT;
-    if ( globals->cGlobals.timerProcs[TIMER_COMMS] != 0 ) {
-        XP_U32 now = util_getCurSeconds( globals->cGlobals.params->util );
-        XP_U32 then = globals->nextTimer;
-        if ( now >= then ) {
-            result = 0;
-        } else {
-            result = (then - now) * 1000;
+    XWTimerReason ii;
+    XP_U32 now = util_getCurSeconds( globals->cGlobals.params->util );
+
+    now *= 1000;
+
+    for ( ii = 0; ii < NUM_TIMERS_PLUS_ONE; ++ii ) {
+        TimerInfo* tip = &globals->cGlobals.timerInfo[ii];
+        if ( !!tip->proc ) {
+            XP_U32 then = tip->when * 1000;
+            if ( now >= then ) {
+                result = 0;
+                break;          /* if one's immediate, we're done */
+            } else {
+                then -= now;
+                if ( result == -1 || then < result ) {
+                    result = then;
+                }
+            }
         }
     }
     return result;
@@ -914,6 +931,31 @@ figureTimeout( CursesAppGlobals* globals )
 # define figureTimeout(g) INFINITE_TIMEOUT
 #endif
 
+static void
+fireCursesTimer( CursesAppGlobals* globals )
+{
+    XWTimerReason ii;
+    TimerInfo* smallestTip = NULL;
+
+    for ( ii = 0; ii < NUM_TIMERS_PLUS_ONE; ++ii ) {
+        TimerInfo* tip = &globals->cGlobals.timerInfo[ii];
+        if ( !!tip->proc ) { 
+            if ( !smallestTip ) {
+                smallestTip = tip;
+            } else if ( tip->when < smallestTip->when ) {
+                smallestTip = tip;
+            }
+        }
+    }
+
+    if ( !!smallestTip ) {
+        XP_ASSERT( util_getCurSeconds( globals->cGlobals.params->util ) 
+                   >= smallestTip->when );
+        linuxFireTimer( &globals->cGlobals, 
+                        smallestTip - globals->cGlobals.timerInfo );
+    }
+}
+
 /* 
  * Ok, so this doesn't block yet.... 
  */
@@ -930,7 +972,7 @@ blocking_gotEvent( CursesAppGlobals* globals, int* ch )
 
     if ( timeout != INFINITE_TIMEOUT && numEvents == 0 ) {
 #ifdef XWFEATURE_RELAY
-        linuxFireTimer( &globals->cGlobals, TIMER_COMMS );
+        fireCursesTimer( globals );
 #endif
     } else if ( numEvents > 0 ) {
 	
@@ -1360,6 +1402,10 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
     g_globals.cp.showBoardArrow = XP_TRUE;
     g_globals.cp.showRobotScores = params->showRobotScores;
     g_globals.cp.hideTileValues = params->hideValues;
+#ifdef XWFEATURE_SLOW_ROBOT
+    g_globals.cp.robotThinkMin = params->robotThinkMin;
+    g_globals.cp.robotThinkMax = params->robotThinkMax;
+#endif
 
     dict = params->dict;
 
diff --git a/xwords4/linux/gtkmain.c b/xwords4/linux/gtkmain.c
index d80dcbc4a..c1e5ab59c 100644
--- a/xwords4/linux/gtkmain.c
+++ b/xwords4/linux/gtkmain.c
@@ -1297,8 +1297,8 @@ gtk_util_setTimer( XW_UtilCtxt* uc, XWTimerReason why,
         XP_ASSERT( 0 );
     }
 
-    globals->cGlobals.timerProcs[why] = proc;
-    globals->cGlobals.timerClosures[why] = closure;
+    globals->cGlobals.timerInfo[why].proc = proc;
+    globals->cGlobals.timerInfo[why].closure = closure;
     XP_ASSERT( newSrc != 0 );
     globals->timerSources[why-1] = newSrc;
 } /* gtk_util_setTimer */
diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c
index 5c6ab90cc..c1e8df101 100644
--- a/xwords4/linux/linuxmain.c
+++ b/xwords4/linux/linuxmain.c
@@ -567,10 +567,11 @@ linux_util_makeStreamFromAddr( XW_UtilCtxt* uctx, XP_U16 channelNo )
 void
 linuxFireTimer( CommonGlobals* cGlobals, XWTimerReason why )
 {
-    XWTimerProc proc = cGlobals->timerProcs[why];
-    void* closure = cGlobals->timerClosures[why];
+    TimerInfo* tip = &cGlobals->timerInfo[why];
+    XWTimerProc proc = tip->proc;
+    void* closure = tip->closure;
 
-    cGlobals->timerProcs[why] = NULL;
+    tip->proc = NULL;
 
     (*proc)( closure, why );
 } /* fireTimer */
diff --git a/xwords4/linux/main.h b/xwords4/linux/main.h
index 6d50b0440..26bb4b269 100644
--- a/xwords4/linux/main.h
+++ b/xwords4/linux/main.h
@@ -120,6 +120,12 @@ typedef void (*AddAcceptorFunc)(int listener, Acceptor func,
 typedef struct LinSMSData LinSMSData;
 #endif
 
+typedef struct _TimerInfo {
+    XWTimerProc proc;
+    void* closure;
+    XP_U32 when;                /* used only for ncurses */
+} TimerInfo;
+
 struct CommonGlobals {
     LaunchParams* params;
 
@@ -150,8 +156,7 @@ struct CommonGlobals {
     LinSMSData* smsData;
 #endif
 
-    XWTimerProc timerProcs[NUM_TIMERS_PLUS_ONE];
-    void* timerClosures[NUM_TIMERS_PLUS_ONE];
+    TimerInfo timerInfo[NUM_TIMERS_PLUS_ONE];
 };
 
 #endif