module IGSProtocol

  UNKNOWN	=  0
  AUTOMAT	=  35 	# Automatch anouncement*/
  AUTOASK	=  36 	# Automatch accept	*/
  CHOICES = 38 	# game choices		*/
  CLIVRFY = 41	# Client verify message */
  BEEP	=  2 	# \7 telnet 		*/
  BOARD	=  3	# Board being drawn 	*/
  DOWN	=  4	# The server is going down */
  ERROR	=  5	# An error reported	*/
  FIL	=  6	# File being sent	*/
  GAMES	=  7	# Games listing	*/
  HELP	=  8	# Help file		*/
  INFO	=  9	# Generic info		*/
  LAST	= 10	# Last command		*/
  KIBITZ	= 11	# Kibitz strings	*/
  LOAD	= 12	# Loading a game	*/
  LOOK_M	= 13	# Look 		*/
  MESSAGE	= 14	# Message lising	*/
  MOVE	= 15	# Move #:(B) A1	*/
  OBSERVE	= 16	# Observe report	*/
  PROMPT	=  1	# A Prompt (never)	*/
  REFRESH	= 17	# Refresh of a board	*/
  SAVED	= 18	# Stored command	*/
  SAY	= 19	# Say string		*/
  SCORE_M	= 20	# Score report		*/
  SGF_M	= 34	# SGF variation	*/
  SHOUT	= 21	# Shout string		*/
  SHOW 	= 29	# Shout string		*/
  STATUS	= 22	# Current Game status	*/
  STORED	= 23	# Stored games		*/
  TEACH	= 33	# teaching game	*/
  TELL	= 24	# Tell string		*/
  DOT	= 40	# your . string	*/
  THIST	= 25	# Thist report		*/
  TIM	= 26	# times command	*/
  TRANS	= 30	# Translation info	*/
  TTT_BOARD= 37 	# tic tac toe		*/
  WHO	= 27	# who command		*/
  UNDO	= 28	# Undo report		*/
  USER	= 42	# Long user report	<-- last */
  VERSION = 39	# IGS VERSION: IGS entry on %02d - %02d - %04d\r\n
      #	 comes out just as the last piece of info
      #	 after verification of the password.
      #	 mm - dd - yyyy <== last Message Type value */
  YELL	= 32	# Channel yelling	*/


  ADJOURN = 48  	# Multigame adjourn	
  IGS = 46	# multi listing of players
  CAPTURE =  47	# Capture messages	
  FOLLOWS	= 45 	# A follow pl messages.
  GOERR	= 50	# An error in a move 	
  REGLOG	= 44	# The reregister reg log
  REMOVING = 49	# Multigame stone removal
  SAY_MG	= 51 	# Say multigame	
  SGF_F	= 43	# SGF command output  

  STATE=['LOGON',  # initial state */
      'PASSWORD',  # getting password */
      'PASSWD_NEW',  # verifiying password: not used, registration */
      'PASSWD_CONFIRM',  # ditto */
      'REGISTER',  # not used */
      'WAITING',  # After login the basic state */
      'PLAYING',  # Playing a game */
      'SCORING',  # Scoring a game */
      'OBSERVING',  # Observing (and playing?) a game */
      'TEACHING',  # In teaching mode, can move for W and B */
      'COMPLETE']  # game complete */

 # status :
 #  22 white rank captured time <byo-yomi stones> T|F komi handicap
 #  22 black rank captured time <byo-yomi stones> T|F komi handicap
 # 0: A col
 # ...
 # 18: T col
 #9 {Game 24: luciano vs tyamano : W 78.5 B 56.0}

 #               0:  Black      4:  White Territory
 #               1:  White      5:  Black Territory
 #               2:  Empty      6:  Starpoint
 #               3:  Dame       7:  Counted

  S_BLACK   = ?0
    S_WHITE   = ?1
    S_EMPTY   = ?2
    S_DAME    = ?3
    S_W_POINT = ?4
    S_B_POINT = ?5
    S_HOSHI   = ?6
    S_COUNTED = ?7

    HANDICAP19=[]

    HANDICAP19[2] = ['D4', 'Q16']
    HANDICAP19[3] = HANDICAP19[2] + ['D16']
    HANDICAP19[4] = HANDICAP19[3] + ['Q4']
    HANDICAP19[5] =  HANDICAP19[4] + ['K10']
    HANDICAP19[6] = HANDICAP19[4] + ['D10', 'Q10'] 
    HANDICAP19[7] = HANDICAP19[6] + ['K10']
    HANDICAP19[8] = HANDICAP19[6] + ['K4', 'K16']
    HANDICAP19[9] = HANDICAP19[8] + ['K10']

    HANDICAP13=[]

    HANDICAP13[2] = ['D4', 'K10']
    HANDICAP13[3] = HANDICAP13[2] + ['D10']
    HANDICAP13[4] = HANDICAP13[3] + ['K4']
    HANDICAP13[5] =  HANDICAP13[4] + ['G7']
    HANDICAP13[6] = HANDICAP13[4] + ['D7', 'K7'] 
    HANDICAP13[7] = HANDICAP13[6] + ['G7']
    HANDICAP13[8] = HANDICAP13[6] + ['G4', 'G10']
    HANDICAP13[9] = HANDICAP13[8] + ['G7']

    HANDICAP9=[]

    HANDICAP9[2] = ['C3', 'G7']
    HANDICAP9[3] = HANDICAP9[2] + ['C7']
    HANDICAP9[4] = HANDICAP9[3] + ['G3']
    HANDICAP9[5] =  HANDICAP9[4] + ['E5']
    HANDICAP9[6] = HANDICAP9[4] + ['C5', 'G5'] 
    HANDICAP9[7] = HANDICAP9[6] + ['E5']
    HANDICAP9[8] = HANDICAP9[6] + ['E3', 'E7']
    HANDICAP9[9] = HANDICAP9[8] + ['E5']


	#	debug
	#for i in 2..9 
	#  puts HANDICAP19[i].inspect 
	#end
end

class Badline <  StandardError
end

class Badmove <  StandardError
end


class Move


  def Move.to_cr(coords)
    m=/([A-T])(\d{1,2})/.match(coords)
    raise(Badmove,"Bad coordinates: #{coords}") if m.nil?
    return m[1],m[2]
  end

  attr_reader :number, :player, :coords, :pris, :action, :handicap

  def initialize(line)
    m= /(\d+)\(([BW])\): (.*)/.match(line)
    raise Badline.new("not a game move: " + line) if m.nil?
    @line = line

    @number = m[1].to_i
    @player = m[2]
    move    = m[3]

    r=/(Handicap (\d))|(Pass)|(([A-T]\d{1,2})( (.*))?)/.match(move)
                                                              raise Badmove.new("not a game move: " + move) if r.nil?


                                                              if not r[1].nil?
                                                                @action='Handicap'
                                                                @handicap=r[2].to_i
                                                              elsif not r[3].nil?
                                                                @action='Pass'
                                                              else
                                                                @action='Move'
                                                                @coords = r[5]
                                                                @pris = r[7].split(' ') if r[7]
                                                              end

  end

  def to_s

    str= "#@number(#@player): " 
    case @action
    when 'Move'
      str += @coords
    when 'Handicap'
      str += "Handicap #@handicap"
    when 'Pass'
      str += 'Pass'
    end
  end
end


class GameHeader
# Game 237 I: MHASHIMOTO (0 536 15) vs openlog (1 598 24)
  attr_reader :number, :white, :black, :w_pris, :b_pris, :w_clock, :b_clock, :w_byo, :b_byo, :FR

  def initialize(line)
    m = /^Game (\d+) (.+): (\S+) \((\d+) (-?\d+) (-?\d+)\) vs (\S+) \((\d+) (-?\d+) (-?\d+)\)/.match(line)

    raise  Badline.new("empty game header") if line.nil?
    raise Badline.new("not a game header: " + line) if m.nil? 

    @number =	m[1].to_i
    @FR = 		m[2]
    @white  =	m[3]
    @w_pris =	m[4].to_i
    @w_clock=	m[5].to_i
    @w_byo  =	m[6].to_i
    @black  =	m[7]
    @b_pris =	m[8].to_i
    @b_clock=	m[9].to_i
    @b_byo  =	m[10].to_i

  end
end

module Ranked

  include Enumerable

  def level(rank)
    m = /^(\d+)(.)(\*?)/.match rank

    if m.nil?
      @name =~ /guest/ ? -100 : -99 
    else
      c = (m[2] == 'k' ? -1 : 1)
      d = (m[3] == '*' ? 1 : 0)
      p = (m[2] == 'p' ? 99 : 0)
      p + c * m[1].to_i * 2 + d 
    end
  end

end

class GameInfo

  include Ranked

  attr_reader :line, :number, :w_player, :w_rank, :b_player, :b_rank, :move, :size, :handicap, :komi, :game, :free, :teach, :tournament, :R, :observers, :byo
  def initialize(line)
    @line = line
    m = /^\[ *(\d+)\] +(\S+) \[ *(.+)\] vs\. +(\S+) \[ *(.+)\] \( *(\d+) +(\d+) +(\d) +(-?\d+\.\d) +(\d+) (.)(.)\) \( *(\d+)\)/.match(line)

    raise Badline.new("not a game info: " + line) if m.nil?

    @number = m[1].to_i
    @w_player = m[2]
    @w_rank = m[3]
    @b_player = m[4]
    @b_rank = m[5]
    @move = m[6].to_i
    @size = m[7].to_i
    @handicap = m[8].to_i
    @komi = m[9].to_f
    @byo = m[10].to_i
    @free =(m[11] == 'F')
    @teach =(m[11] == 'T')
    @tournament =(m[11] == '*')
    @game = m[12] # I = go
    @observers = m[13].to_i

  end

  def <=>(other)

    level(other.w_rank) <=> level(w_rank)
  end

def GameInfo.to_s(line)
if  m = /^\[ *(\d+)\] +(\S+) \[ *(.+)\] vs\. +(\S+) \[ *(.+)\] \( *(\d+) +(\d+) +(\d) +(-?\d+\.\d) +(\d+) (.)(.)\) \( *(\d+)\)/.match(line)


id = $1
str=""
for i in 1..m.length
str <<  "{#{m[i]}} "
end
return id,str
else
return nil,nil
end
end
end

#22 luciano 19k* 11 379 14 T 0.5 0
#22 tyamano 21k* 4 468 13 T 0.5 0
#22  0: 4144411055501114444
# ...
#22 18: 4444413000141105555

class GameStatus
  attr_reader :w_player, :b_player, :w_rank, :b_rank, :w_pris, :b_pris, :w_clock, :b_clock, :w_byo, :b_byo, :w_TIF, :b_TIF

  def initialize(lines)
   # return unless lines
    pat = /^(\S+) *(\S+) +(\d+) (\d+) (-?\d+) (.) .*/
    line = lines.shift
    m= pat.match(line)
    raise Badline.new("not a game status " + line) if m.nil?
    @w_player = m[1]
    @w_rank = m[2]
    @w_pris = m[3].to_i
    @w_clock = m[4].to_i
    @w_byo = m[5].to_i
    @w_TIF = m[6]

    line = lines.shift
    m= pat.match(line)
    raise Badline.new("not a game status: " + line) if m.nil?
    @b_player = m[1]
    @b_rank = m[2]
    @b_pris = m[3].to_i
    @b_clock = m[4].to_i
    @b_byo = m[5].to_i
    @b_TIF = m[6]

    @status = Array.new(19) 

    lines.each { |line|
      m= /(\d+): (\d+)/.match(line)
      raise Badline.new("not a game status: " + line) if m.nil?
      @status[m[1].to_i] = m[2]
    }

  end

  def [](col,row)
#	@status[col][- row - 1]
    @status[col][row]
  end
end

  # 9 {Game 84: jantje vs Taz : W 57.5 B 82.0}
   # 20 satanas (W:O): 24.5 to diabolicum (B:#): 34.0
   #{Game 44: tontonlolo vs satanas has adjourned.}
class GameResult

  attr_reader :number, :w_score, :b_score, :message, :w_player, :b_player
  def initialize(line)
    if m = /^\{Game (\d+): \S+ vs \S+ (: (W (\S+) B (\S+))|.*)\}/.match(line)
      @number = m[1].to_i
      if m[3].nil?
        @message = m[2]
      else
        @w_score = m[4].to_f
        @b_score = m[5].to_f
      end
    elsif m = /^(\S+).*: (\S+) to (\S+).*: (\S+)/.match(line)
      @w_player= m[1]
      @w_score = m[2].to_f
      @b_player= m[3]
      @b_score = m[4].to_f
    else
      raise Badline.new("not a game result: " + line) 
    end
  end

end

    #42    satanas  client testing  France    7k   23/  13  -   -   16s    -X default
   #   Taihei*                  NET       6d   -1/  -1  -   80   4s    -- default
class UserInfo
  include Ranked

  attr_reader :name, :info, :country, :rank, :won, :lost, :observing, :idle, :messages, :game, :language
  attr_accessor :playing, :flags, :obs, :play # rajouts pour wlist.tcl

  def initialize(line)
    m= /^ *(\S+)  (.{1,14})  (.+)  (\S+) +(-?\d+)\/ *(-?\d+) +(\d+|-) +(\d+|-) +(\S+)    (.)(.) (.+)/.match(line)
    if m.nil?

      raise Badline.new("bad user info: " + line) if m.nil?
    end

    @name=m[1]
    @info=m[2]
    @country=m[3]
    @rank=m[4]
    @won=m[5]
    @lost=m[6]
    @observing=m[7] if m[7] != '-'
	@obs=m[7]
    @playing=m[8] if m[8] != '-'
	@play=m[8]
    @idle= m[9]
    @messages=m[10]
    @game=m[11]
    @language=m[12]
	@flags=m[10]+m[11]

    @info.delete!("^ -Z","^a-z")
#@info.delete!('\\')
#	@info= '<none>' if @info.empty?

  end


  def <=>(other)
    level(other.rank) <=> level(rank)
  end

def to_s
"#@name {#@info} {#@country} #@rank #@won #@lost {#@obs} {#@play} #@idle #@flags"
end

def UserInfo.to_s(line)
 m= /^ *(\S+)  (.{1,14})  (.+)  (\S+) +(-?\d+)\/ *(-?\d+) +(\d+|-) +(\d+|-) +(\S+)    (.)(.) (.+)/.match(line)
id = $1
str=""
for i in 1...m.length
str <<  "{#{m[i]}} "
end
return id,str

end


end
=begin
9 Game:        go (1)
9 Language:    default
9 Rating:      5k*  24
9 Rated Games:    2275
9 Rank:  3k  26
9 Wins:       1282
9 Losses:     1195
9 Idle Time:  (On server) 2s
9 Address:  carpentr@magick.net
9 Reg date: Sun Jun 18 05:05:29 1995
9 Info:  No add time, No undo, just good Go
9 Defaults (help defs):  time 90, size 19, byo-yomi time 10, byo-yomi stones 25




=end

class PlayerStats

  attr_reader :name, :game, :language, :rating, :rating_nb, :rated_games, :rank, :rank_nb, :wins, :losses
  attr_reader :playing, :idle_time, :address, :reg_date, :info, :defaults, :last_access_GMT, :last_access_local


  def initialize(lines)
    lines.each { |line|
      case line
      when /Player: *(\S+)/
        @name= $1
      when /Game: *(\S+)/
        @game= $1
      when /Language: *(\S+)/
        @language= $1
      when /Rating: *(\S+) +(\d+)/
        @rating= $1
        @rating_nb= $2.to_i
      when /Rated Games: *(\d+)/
        @rated_games= $1
      when /Rank: *(\S+) +(\d+)/
        @rank= $1
        @rank_nb= $2.to_i
      when /Wins: *(\d+)/
        @wins= $1.to_i
      when /Losses: *(\d+)/
        @losses= $1.to_i
      when /Idle Time:  \(On server\) (\S+)/
        @idle_time= $1
      when /Playing in game: *(\d+)/
        @playing= $1.to_i
      when /Address: *(.+)/
        @address= $1
      when /Reg date: (.+)/
        @reg_date= $1
      when /Info: (.*)/
        @info= $1
      when /Defaults.*:  (.*)/
        @defaults= $1
      when /Last Access\(GMT\):   \(Not on\) *(.*)/
        @last_access_GMT= $1
      when /Last Access\(local\): \(Not on\) *(.*)/
        @last_access_local= $1
      end
    }
  end
end










