#
# == epcb/common
# ExcelPettyCashBookコマンドラインツールの共通機能、共通クラスをまとめたファイル。
#
# Revision:: $Id$
#
require 'parsedate'
require 'log'
require 'win32ole-ext'
require 'epcb/cli'
require 'epcb/errors'
require 'epcb/feature'

module EPCB
  # 生成するCSVやExcelPettyCashBookのバージョン
  TARGET_VERSION = "1.2"

  SUBC_CSV = "gencsv"
  SUBC_EXCEL = "genexcel"
  SUBC_ALL = "genall"

  SUBC_IMPORT = "import"
  SUBC_EXPORT = "export"

  # CSVのシート名につけるプリフィックス
  CSV_SHEET_PREFIX = "$$"
  #   CSV_COL_SEP = ?,
  # CSVの行セパレータ
  CSV_LINE_SEP = "\r\n"

  # \r,\nをエスケープする
  def EPCB.escape(str)
    return str if str.nil?
    s = str.gsub(/\r/, "\\r")
    s = str.gsub(/\n/, "\\n")
    return s
  end

  # マスタシートかどうか判定する。
  def EPCB.master_sheet?(name)
    return (EPCB::MASTER_SHEET_NAME == name)
  end

  # プリファレンスシートかどうか判定する。
  def EPCB.prefs_sheet?(name)
    return (EPCB::PREFS_SHEET_NAME == name)
  end

  # オプションの--source-versionまたはExcelPettyCashBookから
  # 移行元のExcelPettyCashBookのバージョンを取得する。
  def EPCB.get_source_version(eutil)
    ver = nil
    if $options.source_version.nil?
      # ExcelPettyCashBookのマクロからバージョンを取得
      ver = eutil.version_from_workbook
      if ver.nil?
        ver = "1.0.0"
      end
    else
      ver = $options.source_version
    end
    return ver
  end

  # 引数のversionに対応するインスタンスを生成する。
  # === ARGS
  # class_name:: 生成するインスタンスのクラス名
  # version:: 生成したいインスタンスのバージョン(例: "1.1.0")
  # eutil:: ExcelUtilクラスのインスタンス。
  #         +version+ を指定している場合は nil でもOK。
  # args:: 生成するオブジェクトのコンストラクタに渡す引数
  def EPCB.new_specific_instance(class_name, eutil,
                                 version = nil, *args)
    if version.nil?
      version = get_source_version(eutil)
    end
    # minor2を切り捨てて、"."を"_"に置き換えてからインスタンス生成
    ver = truncate_minor2(version)
    ver.gsub!(/\./, "_")
    #Log::debugln("new_specific_instance() #{class_name}_#{ver}")
    instance = nil
    begin
      instance = eval("#{class_name}_#{ver}").new(*args)
    rescue NameError => e
      v = version
      raise(UnknownVersionError, "Unknown version \"#{v}\"")
    end
    return instance
  end

  # オプションで指定されたバージョンのFeatureインスタンスを生成する。
  # === ARGS
  # eutil:: ExcelUtilインスタンス
  # ver:: 生成するFeatureのバージョン
  # genexcel:: ExcelPettyCashBookを生成する処理から呼び出しているかどうかのフラグ
  def EPCB.new_feature(eutil, ver = nil, genexcel = false)
    ver = get_source_version(eutil) if ver.nil?
    #Log::voutln("version = #{ver}")
    begin
      feature = new_specific_instance("Feature", eutil, ver, eutil)
    rescue UnknownVersionError => e
      # ExcelPettyCashBookを生成する処理から呼び出している場合は、
      # --templateで指定されたワークブックのバージョン情報が
      # 未知である旨のエラーをraiseする
      if genexcel
        raise(UnknownWorkbookVersionError, e.message)
      else
        raise(e)
      end
    end
  end

  # x.y.z のバージョン文字列を x.y の部分だけ返す。
  def EPCB.truncate_minor2(version)
    return nil if version.nil?
    if /^(\d+)\.(\d+)\.(\d+)$/ =~ version
      return "#{$1}.#{$2}"
    end
    return version
  end

  #
  # Excel関連のユーティリティクラス
  #
  class ExcelUtil
    attr_reader :excel

    def initialize()
      @excel = nil
    end

    public
    def self.to_yyyymmdd_format(date_str, sep = "/")
      if date_str.nil? || date_str.empty?
        return nil
      end
      d = ParseDate.parsedate(date_str)
      return "#{d[0]}#{sep}#{d[1]}#{sep}#{d[2]}"
    end

    # Excelインスタンスを生成する
    # === RETURNS
    # Excelインスタンス
    def new_excel
      if @excel.nil?
        @excel = Excel.new(true, true)
      end
      return @excel
    end

    # このオブジェクトが持つExcelインスタンスを破棄する
    def destroy_excel
      unless @excel.nil?
        @excel.quit
        @excel = nil
      end
    end

    # 引数+path+のExcelファイルを開いてアクティブにする。
    # === ARGS
    # path:: Excelファイルのパス
    def open_workbook_and_activate(path, display_alerts = true)
      new_excel
      @excel.displayAlerts = display_alerts
      workbook = @excel.workbooks.open(path)
      workbook.activate
      return workbook
    end

    # 引数+name+がデータシート名として正しいか判定する。
    def is_valid_data_sheet_name(name)
      new_excel
      return @excel.run("IsValidDataSheetName", name)
    end

    # アクティブなシートの+Initialize+マクロを呼ぶ。
    def initialize_on_active_sheet()
      new_excel
      @excel.run("Initialize")
    end

    # アクティブなシートの+GetOffset+マクロを呼ぶ。
    def get_offset(line, column)
      new_excel
      return @excel.run("GetOffset", line, column)
    end

    # ExcelPettyCashBookのバージョンをワークブックから取得する。
    def version_from_workbook
      begin
        new_excel
        return @excel.run("Const_VERSION")
      rescue WIN32OLERuntimeError => e
        return nil
      end
    end
  end #ExcelUtil#

end
