#
# == cli
# コマンドラインアプリケーションに共通な機能を提供する。
#
# Revision:: $Id$
#

#require 'optparse'

module CLI
  # コマンドの終了ステータス
  class ExitStatus
    # 正常に処理が終わった
    OK = 0
    # コマンドライン引数に間違いや抜けがある
    ARGUMENT_ERROR = 110
    # オプションの指定が足りない
    OPTION_UNSATISFIED = 111
    # IOエラーが発生した
    IO_ERROR = 120
    # 指定されたファイルが存在しない
    FILE_NOT_FOUND = 121
    # 指定されたディレクトリが存在しない
    DIR_NOT_FOUND = 122
    # 指定されたファイルはディレクトリ
    FILE_IS_DIR = 123
    # 指定されたディレクトリはディレクトリではない
    FILE_IS_NOT_DIR = 124
    # 未知のエラーが発生した
    UNEXPECTED_ERROR = 255
  end #ExitStatus#

  #
  # コマンドラインエラークラス。
  #
  class CLIError < StandardError
    attr_reader :code

    def initialize(message, code = ExitStatus::UNEXPECTED_ERROR)
      super(message)
      @code = code
    end
  end #CLIError#

  # "ファイルがディレクトリ"の旨のエラーメッセージと共にCLIErrorをraiseする。
  # === ARGS
  # path:: エラーになったパス
  def file_is_dir(path)
    raise(CLIError.new("\"#{path}\" is directory.",
                       ExitStatus::FILE_IS_DIR))
  end

  # "ファイルがディレクトリではない"の旨のエラーメッセージと共にCLIErrorをraiseする。
  # === ARGS
  # path:: エラーになったパス
  def file_is_not_dir(path)
    raise(CLIError.new("\"#{path} is not directory.",
                       ExitStatus::FILE_IS_NOT_DIR))
  end

  # "ファイルがない"という旨のエラーメッセージと共にCLIErrorをraiseする。
  # === ARGS
  # file:: エラーになったパス
  def file_not_found(file)
    raise(CLIError.new("File \"#{file}\" not found.",
                       ExitStatus::FILE_NOT_FOUND))
  end

  # "ディレクトリがない"という旨のエラーメッセージと共にCLIErrorをraiseする。
  # === ARGS
  # dir:: エラーになったパス
  def dir_not_found(dir)
    raise(CLIError.new("Directory \"#{dir}\" not found.",
                       ExitStatus::DIR_NOT_FOUND))
  end

  # ファイルが存在することを確認する。
  # ファイルが存在しない場合はCLIErrorをraiseする。
  # === ARGS
  # file:: 調べるファイルのパス
  def ensure_file_exist(file)
    if FileTest.directory?(file)
      file_is_dir(file)
    elsif !FileTest.exist?(file)
      file_not_found(file)
    end
  end

  # ディレクトリが存在することを確認する。
  # ディレクトリが存在しない場合はCLIErrorをraiseする。
  # === ARGS
  # dir:: 調べるディレクトリのパス
  def ensure_dir_exist(dir)
    if !FileTest.exist?(dir)
      directory_not_found(dir)
    elsif !FileTest.directory?(dir)
      file_is_not_dir(dir)
    end
  end

  # 例外+e+のバックトレースを標準エラー出力に出力する。
  # === ARGS
  # e:: 例外
  def print_backtrace(e, insert_new_line = true)
    $stderr.puts("") if insert_new_line
    $stderr.puts(e.inspect)
    e.backtrace.each do |s|
      $stderr.puts("    #{s}")
    end
  end

  # 引数の例外のメッセージを標準エラー出力に出力する。
  # === ARGS
  # e:: 例外
  def report_error(e)
    eoutln(e.message)
  end

  # 致命的エラーを報告する。
  # 引数の例外のメッセージとバックトレースを標準エラー出力に出力する。
  # === ARGS
  # e:: 例外
  def report_fatal_error(e)
    report_error(e.message)
    $stderr.puts("")
    print_backtrace(e)
  end

  module_function :file_not_found, \
  :dir_not_found, :file_is_dir, :file_is_not_dir, :ensure_file_exist, \
  :ensure_dir_exist,  :report_error, :print_backtrace, :report_fatal_error

  #
  # コマンドラインアプリケーションの基底クラス。
  #
  class Application
    def initialize
    end

    def run
    end

    def destroy
    end
  end #Application#

end #CLI#
