require 'gosgf.rb'
require 'gofun.rb'
require 'ugi2sgf.rb'

require 'md5'
require 'cgi-lib'

$allow_renumbering_when_same_colour = false
$handle_variations    = true
$max_move_per_diagram = 400
$draw_coordinates     = true
$vary_font            = true
$colours =
{
  # Black
  'b' => '#000000',
  # Ban
  'h' => '#C89650',
  # White
  'w' => '#FFFFFF',
  # Messages
  'm' => '#787878'
}

def kifuta(game, bansize, move1, move2)
  ban = Goban.new
  ban.setsize bansize
  ban.setcapturemode true
  
  # Send the settings to the graphics generator.
  print "SET DC ", ($draw_coordinates ? '1' : '0'), "\n"
  print "SET VF ", ($vary_font        ? '1' : '0'), "\n"
  print "SET BC ", $colours['b'], "\n"
  print "SET AC ", $colours['h'], "\n"
  print "SET WC ", $colours['w'], "\n"
  print "SET MC ", $colours['m'], "\n"
  
  (0..(move1-1)).each do |moveno|
    thismove = game[moveno] or next
    thismove.each do |loc,what|
      next if loc == 'C' or loc == 'S'
      case what
        when 'AB', 'B'; ban.setcolour(loc.getxcoord, loc.getycoord, BLACK) if loc!='tt'
        when 'AW', 'W'; ban.setcolour(loc.getxcoord, loc.getycoord, WHITE) if loc!='tt'
        when 'AE'     ; ban.setcolour(loc.getxcoord, loc.getycoord, EMPTY) if loc!='tt'
      end
    end
  end
  
  ban.setcapturemode false
  
  firstplay   = Hash.new
  cappos      = Hash.new
  
  identifiers = Hash.new
  
  syms = [TRIANGLE, SQUARE,
          'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J',
          'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T',
          'U', 'V', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
          'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p',
          'q', 'r', 's', 't', 'u', 'v', 'w', 'y', 'z']
  symcounter = {BLACK => 0, WHITE => 0}
  
  (move1..move2).each do |moveno|
    thismove = game[moveno] or next
    thismove.each do |loc,what|
      if loc == 'C' or loc == 'S'
        # Comments, ignore
        next
      end
      case what
        when 'AB'
          ban.setcolour(loc.getxcoord, loc.getycoord, BLACK)
        when 'AW'
          ban.setcolour(loc.getxcoord, loc.getycoord, WHITE)
        when 'AE'
          puts "Ouch!"
        when 'B', 'W'
          color = (what == 'B' ? BLACK : WHITE)
          if loc=='tt'
            # Pass
            next
          end
          
          x = loc.getxcoord
          y = loc.getycoord
          pos = ban.getpos(x,y)

          #print "Play at #{x},#{y} (#{what})\n"
          captures = ban.setcolour x,y, color
          
          if cappos[pos]
            if !firstplay[pos]
              # Playing on unnamed spot
              if ban.getcolour(x,y) == color and !identifiers[pos] \
              and $allow_renumbering_when_same_colour
                # Same colour as before, ignore this occassion
                ban.setsymbol loc.getxcoord, loc.getycoord, moveno
                if !firstplay[pos]
                  firstplay[pos] = [moveno, color]
                end
              else
                # Make an identifier for the spot
                if !identifiers[pos]
                  # TODO: Somehow ensure an unique symbol here!
                  symcolour = ban.getcolour(x,y)
                  sym = syms[symcounter[symcolour] % syms.size]
                  symcounter[symcolour] += 1
                  ban.setsymbol x, y, sym
                  identifiers[pos] = [sym, symcolour]
                end
                identifiers[pos] << (what + moveno.to_s)
              end
            else
              # Playing on a previously occupied spot

              # This identifies the point of play:
              prevmove,prevcolor = firstplay[pos]
              
              identifiers[prevmove] = [prevcolor] if !identifiers[prevmove]
              identifiers[prevmove] << (what + moveno.to_s)
            end
            # Don't set a symbol to a point that already was there
          else
            ban.setsymbol loc.getxcoord, loc.getycoord, moveno
            if !firstplay[pos]
              firstplay[pos] = [moveno, color]
            end
          end
          
          captures.each { |pos, colour|
            if !cappos[pos]
              # Remember the capture
              cappos[pos] = [moveno, colour]
            end
          }
      end
    end
  end
  
  print ban.getrecord
  
  identifiers.each do |basemovenum, movelist|
    if ban.issymbol(movelist[0]) or movelist[0].kind_of?(String)
      # Symbol!
      print 'NOTE'
      sym=false
      basecolor=false
      movelist.each { |c|
        if !sym; sym=c; next; end
        if !basecolor; basecolor=c; next; end
        print ' ', c
      }
      print '=', basecolor==BLACK ? 'B' : 'W'
      if ban.issymbol(movelist[0])
        puts ban.getsymbolcode(sym)
      else
        print '"'
        puts sym
      end
    else
      print 'NOTE'
      basecolor=false
      movelist.each { |c|
        if !basecolor; basecolor=c; next; end
        print ' ', c
      }
      print '=', basecolor==BLACK ? 'B' : 'W'
      puts basemovenum
    end
  end
  
  # 
  # identifiers:
  #  Useful for appnotes for ko-takers etc
  #  Contains:
  #   { basemovenum => [ color, pos... ] }
  
  # firstplay:
  #  Contains the first play at given spot.
  #  Contains:
  #   { pos => [moveno, color] }
end

def pelikifu(game, bansize, move1, move2)
  ban = Goban.new
  ban.setsize bansize
  ban.setcapturemode true
  
  (0..move1-1).each do |moveno|
    thismove = game[moveno] or next
    thismove.each do |loc,what|
      next if loc == 'C' or loc == 'S'
      case what
        when 'AB', 'B'; ban.setcolour(loc.getxcoord, loc.getycoord, BLACK) if loc!='tt'
        when 'AW', 'W'; ban.setcolour(loc.getxcoord, loc.getycoord, WHITE) if loc!='tt'
        when 'AE'     ; ban.setcolour(loc.getxcoord, loc.getycoord, EMPTY) if loc!='tt'
      end
    end
  end
  commentlist = Array.new
  (move1..move2).each do |moveno|
    thismove = game[moveno] or next
    thismove.each do |loc,what|
      if loc == 'C' or loc == 'S'
        commentlist << [loc, moveno, what]
        next
      end
      case what
        when 'AB'; ban.setcolour loc.getxcoord, loc.getycoord, BLACK
        when 'AW'; ban.setcolour loc.getxcoord, loc.getycoord, WHITE
        when 'AE'; ban.setcolour loc.getxcoord, loc.getycoord, EMPTY
        when 'B', 'W'
          color = (what == 'B' ? BLACK : WHITE)
          if loc=='tt'
            commentlist << ['S', moveno, "pass"]
            next
          end
          x = loc.getxcoord
          y = loc.getycoord
          captures = ban.setcolour x,y, color
          if captures.size > 0
            plur = captures.size > 1 ? "stones" : "stone"
            komm = "captures #{captures.size} #{plur}"
            if captures.size < 3
              komm << ' ('
              c=false
              captures.each { |cappos,capcolor|
                if c;komm << ' ';else;c=true;end
                komm << ban.getposname(cappos)
              }
              komm << ')'
            end
            commentlist << ['S', moveno, komm]
          end
      end
    end    
  end
  
  retval = [commentlist]
  
  while true
    endmove = move2
    if move2 >= move1 + $max_move_per_diagram
      endmove = move1 + $max_move_per_diagram - 1
    end

    # Now we have list of comments and we should also know
    # when to split.
    
    p = IO.pipe
    saved = STDOUT.dup
    STDOUT.reopen p[1]
    p[1].close
    res = ''
    Thread.start {
      kifuta game, bansize, move1, endmove
      STDOUT.reopen saved
    }
    res = p[0].read
    p[0].close
    
    retval << [move1, endmove, res]
    
    move1 = endmove + 1
    break if move1 >= move2 
  end

  return retval
end

def draw(otsikkopohja, data)
  if otsikkopohja.size > 0
    print '<h2>', otsikkopohja, '</h2>'
  end
  print '<table>'
  print '<tr>'
  print '<td valign=top>'
  
  kommentlist = false
  
  data.each do |d|
    if !kommentlist; kommentlist = d; next; end
  
    print '<h3>'
    if d[1] > d[0]
      print 'Moves ', d[0], '-', d[1]
    else
      print 'Move ', d[0]
    end
    puts '</h3>'

    md5 = MD5.md5(d[2]).to_s
    
    f = File.open('img/'+md5+'.txt', 'w')
    f.write(d[2])
    f.close
    
    print '<img src="/go/kifu-', md5, '.png" alt="diagram ', md5, '">'
  end
  
  print '</td><td valign=top style="font-size:80%">'
  
  kommentlist.each do |tab|
    key    = tab[0]
    moveno = tab[1]
    text   = tab[2]
    if key == 'S'
      print '<b>[Move ', moveno, ': ', text, ']</b><br>', "\n"
    else
      print '<b>[Move ', moveno, ']</b><br>', "\n"
      puts CGI.escapeHTML(text).gsub("\n", '<br>')
      #puts '<br>'
    end
  end
  puts '</td></tr></table>'
end

$variationcount=0
def getvariationname
  ret = sprintf('%c', $variationcount + 'A'[0])
  $variationcount += 1
  ret
end

$whiteplay=''
$whiterank=''
$blackplay=''
$blackrank=''
$blackimage=''
$whiteimage=''
$gamedate=''
$gameplace=''
$gameresult=''
$gameevent=''
$gameround=''
$gamecomment=''
$handicap=''
$komi=''

$system=''

$bansize = 19
$variaatiot=Hash.new
def loadsgf(sgf, firstmovenum=0, pohjamoves = Hash.new)
  movenum = firstmovenum
  thismove = Hash.new
  moves = pohjamoves
  begin
    sgf.keys.sort.each do |nodenum|  contents = sgf[nodenum]
      #puts contents.inspect
      continuation=false
      comments = false
      contents.each do |key, values|
        case key
          when 'AB', 'AW', 'AE', 'B', 'W'
                     values.each { |value| value='tt' if value=='';;thismove[value] = key }
          when 'SZ'; values.each { |value| $bansize = value.to_i }
          when 'C';  values.each { |value| thismove[key] = value }
          when 'PW'; $whiteplay = values[0]
          when 'PB'; $blackplay = values[0]
          when 'WR'; $whiterank = values[0]
          when 'BR'; $blackrank = values[0]
          when 'DT'; $gamedate = values[0]
          when 'PC'; $gameplace = values[0]
          when 'RE'; $gameresult = values[0]
          when 'EV'; $gameevent = values[0]
          when 'RO'; $gameround = values[0]
          when 'GC'; $gamecomment = values[0]
          when 'HA'; $handicap = values[0]
          when 'KM'; $komi = values[0]
          when 'FB'; $blackimage = values[0]
          when 'FW'; $whiteimage = values[0]
        end
      end
      contents.each do |key, values|
        case key
          when NEWNODE
            values.each { |subsgf|
              if !continuation; continuation=subsgf; next; end
              if $handle_variations
                comments = "variations:" if !comments
                varname = getvariationname
                comments << ' ' + varname
                
                tmpmoves = moves.dup
                tmpmoves[movenum] = thismove
                $variaatiot[varname] = loadsgf(subsgf, movenum+1, tmpmoves)
              end
            }
        end
      end
      moves[movenum] = thismove
      movenum += 1
      thismove = Hash.new
      if comments
        thismove['S'] = '' if !thismove['S']
        thismove['S'] << (comments + "\n")
      end
      if continuation
        sgf = continuation
        raise
      end
    end
  rescue
    retry
  end
  movenum -= 1
  pelikifu(moves, $bansize, firstmovenum, movenum)
end

def makeimage(s)
  md5 = MD5.md5(s).to_s
  f = File.open('img/' + md5 + '.jpg', 'w')
  f.write(s)
  f.close
  '<img src="/go/img/' + md5 + '.jpg" alt="">'
end

def generoisivu
  sgf = readsgf { yield }

  #dumpsgf sgf

  data = loadsgf sgf
  
print '<table><tr><td>'
print "<pre
>Date: #{$gamedate}
Place: #{$gameplace}
Event: #{$gameevent}   Round: #{$gameround}
Komi: #{$komi}  Handicap: #{$handicap}  Result: #{$gameresult}
Comment: #{$gamecomment}
</pre>"

print '</td><td>'

print '<table><tr>'
 print "<th>White: #{$whiteplay} (#{$whiterank})</th>"
 print "<th>Black: #{$blackplay} (#{$blackrank})</th>"
print '</tr><tr>'
 print '<td>'
 print makeimage($whiteimage),'<br>' if($whiteimage.size > 0)
 print '</td>' 
 print '<td>'
 print makeimage($blackimage),'<br>' if($blackimage.size > 0)
 print '</td>' 
print '</tr></table>'

print '</td></tr></table>'

  draw "", data
  $variaatiot.keys.sort.each { |varname|
    vardata = $variaatiot[varname]
    draw "Variation #{varname}", vardata
  }
end

begin
  while true
    s = STDIN.gets
    break if !s
    break if s == "--\n"
    $allow_renumbering_when_same_colour = s[7]=='1'[0]      if s =~ /^SET AR /
    $handle_variations                  = s[7]=='1'[0]      if s =~ /^SET HV /
    $draw_coordinates                   = s[7]=='1'[0]      if s =~ /^SET DC /
    $vary_font                          = s[7]=='1'[0]      if s =~ /^SET VF /
    $max_move_per_diagram               = s.slice(7,9).to_i if s =~ /^SET MM /
    $colours['b'] = s.slice(7,30).gsub("\n",'')             if s =~ /^SET BC /
    $colours['h'] = s.slice(7,30).gsub("\n",'')             if s =~ /^SET AC /
    $colours['w'] = s.slice(7,30).gsub("\n",'')             if s =~ /^SET WC /
    $colours['m'] = s.slice(7,30).gsub("\n",'')             if s =~ /^SET MC /
  end
  
  $max_move_per_diagram = 2 if $max_move_per_diagram < 2
  
  sgf = STDIN.read
  
  if sgf.ugifile?
    sgf = ugi2sgf(sgf)
  end
  
  generoisivu { sgf }
  #generoisivu { File.open('/home/bisqwit/narf1-Bisqwit1.sgf', 'r').read }
  #generoisivu { File.open('/home/bisqwit/records-long-1.sgf', 'r').read }
rescue String => err
  puts 'Error: ' + err
  exit
rescue StandardError => err
  puts 'Error: ' + err.to_s + ' (trace: ' + err.backtrace.inspect + ')'
  exit
end
