#!wish -f

#======================================================================
# Private internals.  You shouldn't have to worry about these.
#======================================================================

signal error int

proc print_state {} {
  global myserver myport casino casinohost casinoport myname myid mymoney
  global playing mytable
  puts stdout "--------------------------------------------------"
  if {![catch {set myserver; set myport}]} {
    puts stdout "Running $myserver on port $myport"
  }
  if {![catch {set casino; set casinohost; set casinoport}]} {
    puts stdout "Connected to casino $casino on $casinohost, port $casinoport"
  }
  if {![catch {set myname; set myid; set mymoney}]} {
    puts stdout "Logged in as $myname, ID $myid, with $mymoney chips."
  }
  if {![catch {set playing; set mytable}]} {
    puts stdout "[expr $playing?"Playing":"Watching"] table $mytable."
  }
  puts stdout "--------------------------------------------------"
  return
}

#----------------------------------------------------------------------
# process_casino_msg client_obj cmdstr
#
# Main routine for handling messages from the casino.  Checks that
# it's a real poker message, then just eval's it.
#----------------------------------------------------------------------
proc process_casino_msg {client something} {
  global player_cmds
  set something [lindex $something 0]
  if {[lsearch $player_cmds [lindex $something 0]] == -1} {
    error "Non-poker command \"[lindex $something 0]\": must be one of $player_cmds."
  }
  if {[lindex $something 0] == "exit"} exit
  puts stdout "Casino says: $something"
  eval $something
}

proc mylogin {client} {
  puts stdout "Connection request from [$client hostname]"
  $client command process_casino_msg
  return "Player received and accepted your connection request."
}

proc ask_casino {casinocmd} {
  global casino
  puts stdout "Asking casino: $casinocmd"
  set reply [eval $casino send $casinocmd]
  puts stdout "Casino answers: $reply"
  return $reply
}

proc tell_casino {casinocmd} {
  global casino
  puts stdout "Telling casino: $casinocmd"
  set reply [eval $casino send $casinocmd]
  puts stdout "Casino responds: $reply"
  return $reply
}

proc rs {} {source player.tcl}

proc upon_new_cards {cmd} {
  proc cards {info} {
    global cardsinfo
    eval $cmd $info
  }
}

proc upon_my_turn {cmd} {
  proc your_turn {tocall mymoney maxbet} "eval $cmd \$tocall \$mymoney \$maxbet"
}

proc upon_someone_folded {cmd} {
  proc folded {player} "eval $cmd \$player"
}

proc upon_someone_calls {cmd} {
  proc calls {player amt} "eval $cmd \$player \$amt 0"
  proc raises {player amt raise} "eval $cmd \$player \$amt \$raise"
}

set player_cmds {LOW_CASH PLAY O_PLAY WATCH O_WATCH YOUR_TURN CARDS
  O_CALLS O_RAISES O_FOLDED LOW_CASH O_JOIN O_LEAVE ANTE FINALCARDS
  WINNER
}

#======================================================================
# Public: Client procedures called by remote Poker server.
# These should be rewritten for each poker-playing program.
#======================================================================

proc LOW_CASH {args} {}
proc PLAY {args} {}
proc O_PLAY {name args} {}
proc WATCH {args} {}
proc O_WATCH {name args} {}
proc YOUR_TURN {j m n args} {}
proc CARDS {args} {}
proc O_CALLS {p j} {}
proc O_RAISES {p j r} {}
proc O_FOLDED {p args} {}
proc LOW_CASH {args} {}
proc O_JOIN {args} {}
proc O_LEAVE {args} {}
proc ANTE {n args} {}
proc FINALCARDS {args} {}
proc WINNER {name args} {}

#======================================================================
# Public: Calls to remote Poker server.
#======================================================================

#----------------------------------------------------------------------
# enter_casino <hostname> <portnum>
#
# Walk into the casino at the given host and port.
#----------------------------------------------------------------------
proc enter_casino {hostname portnum} {
  global myport myserver casino casinohost casinoport
  catch {leave_the_casino}
  set myserver [tcp server -command mylogin]
  $myserver start
  set myport [$myserver config -port]
  puts stdout "Player listening on port $myport."
  set casino [tcp connect $hostname $portnum]
  tell_casino $myport
  set casinohost $hostname; set casinoport $portnum
  set playing 0; set watching 0
  return
}

#----------------------------------------------------------------------
# register <name> <id>
#
# Register your name and secret-ID with the casino.  Take
# control of that ID's chips.  Returns casino's response.
#----------------------------------------------------------------------
proc register {name id} {
  global playing myname myid mymoney
  set result [tell_casino "signon $name $id"]
  set mymoney [lindex $result 0]
  set myname $name; set myid $id
  return $result
}

#----------------------------------------------------------------------
# leave_casino
#
# Leave the casino. Cleans up. Returns casino's response.
#----------------------------------------------------------------------
proc leave_casino {} {
  global myserver myport casino casinohost casinoport myname myid mymoney
  catch {set result [tell_casino logout]}
  catch {$casino close}
  $myserver stop
  unset myserver myport casino casinohost casinoport myname myid mymoney
  return $result
}

#----------------------------------------------------------------------
# look_around
#
# Check out all the tables.  Returns casino's response.
#----------------------------------------------------------------------
proc look_around {} {
  ask_casino tables
}

#----------------------------------------------------------------------
# watch_table <tablenum>
#
# Become a watcher at table #n.  Returns casino's response.
# If you're already playing, requests to drop out after this hand.
#----------------------------------------------------------------------
proc watch_table {n} {
  global mytable playing watching
  set result [tell_casino "watch $n"]
  set mytable $n
  set watching 1; set playing 0
  return $result
}

#----------------------------------------------------------------------
# join_table <tablenum>
#
# Request to be dealt in on the next round at table #n.  Returns
# casino's response.
#----------------------------------------------------------------------
proc join_table {n} {
  global mytable playing watching
  set result [tell_casino "joinTable $n"]
  set mytable $n
  set playing 1; set watching 0
  return $result
}

#----------------------------------------------------------------------
# leave_table
#
# Leave the table. If playing, requests to leave after this hand.
#----------------------------------------------------------------------
proc leave_table {} {
  global mytable playing watching
  set result [tell_casino exitTable]
  set playing 0; set watching 0
  unset mytable
  return result
}

#----------------------------------------------------------------------
# I_fold
#
# Tell the table you fold.
#----------------------------------------------------------------------
proc I_fold {} {
  tell_casino fold
}

#----------------------------------------------------------------------
# I_raise <amt>
#
# Tell the table you raise by <amt> (greater than 0).
#----------------------------------------------------------------------
proc I_raise {n} {
  tell_casino "raise $n"
}

#----------------------------------------------------------------------
# I_call <amt>
#
# Tell the table you call (match the current bet).
#----------------------------------------------------------------------
proc I_call {} {
  tell_casino call
}
