#! /usr/bin/env ruby
#
# PRIME: PRedictive Input Method Editor
# $Id: prime,v 1.7 2004/01/08 06:54:02 komatsu Exp $
#
# Copyright (C) 2001 Satoru Takabayashi <satoru@namazu.org>
# Copyright (C) 2002, 2003 Hiroyuki Komatsu <komatsu@taiyaki.org>
#     All rights reserved.
#     This is free software with ABSOLUTELY NO WARRANTY.
#
# You can redistribute it and/or modify it under the terms of 
# the GNU General Public License version 2.
#

$LOAD_PATH.push(File::dirname($0))

require 'getoptlong'
require 'prime/prime'
require 'prime/session'
require "jcode"

include PogemoServer

PRIME_VERSION = "0.6.6"

class Session < SessionCore
  def initialize (pogemo, inport, outport)
    super
    @name = "prime"
    @version = PRIME_VERSION
    @id = ""

    add_command(:l, [:PATTERN],
		"look up PATTERN with hybrid matching")
    add_command(:lookup_hybrid, [:PATTERN],
		"look up PATTERN with hybrid matching")
    add_command(:lookup_prefix, [:PATTERN],
		"look up PATTERN with prefix matching")
    add_command(:lookup_exact, [:PATTERN],
		"look up PATTERN with exact matching")
    add_command(:learn_word, [:KEY, :VALUE, :PART, :CONTEXT, :SUFFIX, :REST],
		"learn and record a word to the user dictionary", 2)
    add_command(:reset_context, [], "reset context")
    add_command(:set_context, [:CONTEXT], "set context to CONTEXT")
    add_command(:get_env, [:KEY], "get a variable associated with KEY")
    add_command(:get_label, [:PATTERN],
		"get a label string (e.g. hiragana) from a user input.")
    add_command(:preedit_convert_input, [:PATTERN],
                "convert a PATTERN and return a pair of a converted and a pending string.")
    add_command(:refresh, [],
                "refresh the statuses of the conversion engines.")
  end

  def learn_word (key, value, part = nil,
		  context = nil, suffix = nil, rest = nil)
    reply_successful {
      @pogemo.learn_word(key, value, part, context, suffix, rest)
    }
  end

  def l (pattern)
    reply_successful {
      @out.puts @pogemo.lookup_hybrid(pattern).to_text
    }
  end

  def get_env (key)
    reply_successful {
      env = @pogemo.get_env(key)
      if env.kind_of?(String) then
	output = format("string\t%s", env)
      elsif env.kind_of?(Array) then
	output = format("array\t%s", env.join("\t"))
      elsif env.kind_of?(TrueClass) or env.kind_of?(FalseClass) then
	output = format("boolean\t%s", env ? "true" : "false")
      elsif env == nil then
	output = 'nil'
      else
	output = 'unknown'
      end
      @out.puts output
    }
  end

  def get_label (pattern)
    reply_successful {
      @out.puts @pogemo.get_label(pattern)
    }
  end

  def preedit_convert_input (pattern)
    reply_successful {
      @out.puts @pogemo.preedit_convert_input(pattern)
    }
  end

  def set_context (context)
    reply_successful {
      @pogemo.set_context(context)
    }
  end

  def reset_context ()
    reply_successful {
      @pogemo.set_context(nil)
    }
  end
  
  def lookup_hybrid (pattern)
    reply_successful {
      @out.puts @pogemo.lookup_hybrid(pattern).to_text
    }
  end

  def lookup_prefix (pattern)
    reply_successful {
      @out.puts @pogemo.lookup_prefix(pattern).to_text
    }
  end

  def lookup_exact (pattern)
    reply_successful {
      @out.puts @pogemo.lookup_exact(pattern).to_text
    }
  end

  def refresh ()
    reply_successful {
      @pogemo.refresh()
    }
  end
end

def show_usage
  puts "\
Usage: #{command_name} <options>
  -u, --unix-socket=PATH  run as Unix socket server with socket PATH
  -s, --tcp-server=PORT   run as TCP server with port PORT
  -v, --version           show the version and exit
  -h, --help              show this help and exit
      --no-save           do not save learning records
  -d, --debug             run under debug mode
"
end

def command_name
  $0.split('/').last
end

def parse_options
  options = Hash.new

  parser = GetoptLong.new
  parser.set_options(['--help', '-h',           GetoptLong::NO_ARGUMENT],
		     ['--version','-v',		GetoptLong::NO_ARGUMENT],
		     ['--unix-socket',	'-u',	GetoptLong::REQUIRED_ARGUMENT],
		     ['--tcp-server',	'-s',	GetoptLong::REQUIRED_ARGUMENT],
#		     ['--no-save',              GetoptLong::NO_ARGUMENT],
		     ['--debug', '-d',		GetoptLong::NO_ARGUMENT])

  parser.each_option {|option, arg|
    options[option.sub(/^--/, '')] = arg
  }

  if options['version'] then
    puts "#{command_name} #{PRIME_VERSION}"
    exit 1
  end

  if options['no-save'] then
    $PRIME_NO_SAVE = true
  else
    $PRIME_NO_SAVE = false
  end

  if options['help'] then
    show_usage
    exit 1
  end

  return options
end

def main ()
  options = parse_options()

  ## FIXME: Move the position of 'prime-userdict-update'.
  ## FIXME: <komatsu@taiyaki.org> (2003-12-21)
#  system('prime-userdict-update --auto --quiet')

  @prime = Prime.new()

  if options['unix-socket']
    socket_path = options['unix-socket']
    server = UnixSocketServer.new(@prime, socket_path)
  elsif options['tcp-server']
    tcp_port = options['tcp-server']
    server = TaiyakiTCPServer.new(@prime, tcp_port)
  else
    server = StdioServer.new(@prime)
  end

  if options['debug'] or ENV['PRIME_DEBUG'] then
    Dir::ensure(PRIME_USER_DIR + "/logs")
    logfile = PRIME_USER_DIR + "/logs/debug_" +
              Time::new.strftime("%Y%m%d%H%M") + "_" + $$.to_s + ".log"
    server.set_debug(logfile)
  end

  server.accept()
end

trap ("HUP") {
  @prime.refresh()
}
main()
