#!/usr/bin/ruby -w
#
# == Synopsis
#
# Play one move of a Trap the Cap game
# 
# == Usage
# ttc [ -b | --board-size SIZE ] [ -i | --input FILE ] [ -r | --robot ROBOT ] [ -h | --help ]
#
# == Author
# Neil Smith

require 'libttc'
require 'cgi'
require 'open3'
require 'timeout'

# Prevent dangerous operations
$SAFE = 1

class InvalidRobotError < StandardError
end

class NoInputFileError < StandardError
end

class InvalidMoveInHistoryError < StandardError
end

class GameWonInHistoryError < StandardError
end

 
# A table of the known game-playing robots

$ROBOT_NAME_TABLE = {
  'Always clockwise simple' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/1',
  'Clockwise cloud' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/2',
  'GA generation 1006' => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/3'
}

$ROBOT_CODE_TABLE = {
  '1'  => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/1',
  '2'  => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/2',
  '3'  => '/var/www/scripts.njae.me.uk/trap-the-cap/robots/3'
}


# How long the robot has to respond
$ROBOT_TIMEOUT = 10


def generate_output(cgi, returned_move, annotation)
  if returned_move.empty?
    return_part = ""
  else
    return_part = cgi.p { "Result is: " } + "\n" + cgi.h1 { returned_move } + "\n"
  end

  if annotation.empty?
    annotation_part = ""
  else
    annotation_part = cgi.p { annotation }
  end

  cgi.html {
    cgi.head { "\n" + cgi.title{"Move result"} } + "\n" +
    cgi.body { return_part + annotation_part }
    }
end


begin

  cgi = CGI.new("html4")

  chosen_robot = cgi['robot']
  if $ROBOT_NAME_TABLE.has_key? chosen_robot
    chosen_robot_dir = $ROBOT_NAME_TABLE[chosen_robot]
    chosen_robot_dir.untaint
  else
    raise InvalidRobotError, "#{chosen_robot} is not a valid robot code"
  end

  begin
    game, moves, next_roll = Game.read_game(cgi['moves'].downcase.split("\n"))
    game.apply_moves! moves
  rescue InvalidMoveError => error
    raise(InvalidMoveInHistoryError, error.message)
  rescue GameWonNotice => error
    raise(GameWonInHistoryError, error.message)
  end

  current_directory = Dir.pwd
  current_directory.untaint
  Dir.chdir chosen_robot_dir

  returned_move = ""
  returned_error = ""
  robot_input = game.players.length.to_s + "\n" 
  robot_input += (moves.collect {|m| m.to_s}).join("\n") + "\n" if not moves.empty?
  robot_input += next_roll.to_s

#  cgi.out { generate_output(cgi, "", "passing robot #{game.players.length.to_s + "#" + (moves.collect {|m| m.to_s}).join('!\n!') + "#" + next_roll.to_s}!") }
#  cgi.out { generate_output(cgi, "", "passing robot #{robot_input}!") }


  Timeout.timeout($ROBOT_TIMEOUT + 1) do
    Open3.popen3('./runme') do |robot_in, robot_out, robot_err|
      robot_in << robot_input
      robot_in.close_write
      returned_move  = robot_out.gets
      returned_error = robot_err.gets
    end
  end

  Dir.chdir current_directory

#  cgi.out { generate_output(cgi, "", "Returned move #{returned_move}; robot error was #{returned_error}!") }

  raise(InvalidMoveError, "Robot returned error '#{returned_error}'") if returned_error != nil
  raise(InvalidMoveError, "Null move") if returned_move.nil? or returned_move.empty?
  next_move = returned_move.chomp.to_move(game)
  game.apply_move! next_move

#    cgi.out { generate_output(cgi, "", "Applied move #{returned_move}!") }
  cgi.out { generate_output(cgi, returned_move, "")  }

rescue InvalidMoveInHistoryError => error
  cgi.out { generate_output(cgi, "", "Invalid move in history: #{error}") }
#  puts "Invalid move in history: #{error}"
rescue GameWonInHistoryError => error
  cgi.out { generate_output(cgi, "", "Game already won in historic moves: #{error}") }
#  puts "Game already won in historic moves: #{error}"

rescue InvalidMoveError => error
  cgi.out { generate_output(cgi, "", "Robot returned invalid move: #{error}") }
#  puts "Robot returned invalid move: #{error}"
rescue GameWonNotice => error
  cgi.out { generate_output(cgi, returned_move, "Game won: #{error}") }
#  puts "Robot returned #{returned_move}"
#  puts "Game won: #{error}"

rescue InvalidRobotError => error
  cgi.out { generate_output(cgi, "", "Invalid robot selection: #{error}") }
#  puts "Invalid robot selection: #{error}"
rescue Timeout::Error => error
  cgi.out { generate_output(cgi, "", "Robot timed out") }
#  puts "Robot timeout: #{error}"

end