#
# == epcb/excel-parser
#
# Revision:: $Id$
#
require 'epcb/data'
require 'epcb/common'

module EPCB
  #
  # ExcelPettyCashBookを解析するパーサ。
  #
  class ExcelParser
    # コンストラクタ。
    # === ARGS
    # eutil:: ExcelUtilのインスタンス
    def initialize(eutil)
      @eutil = eutil
      @feature = nil
    end

    # Excelシートを解析し、解析結果であるMonthDataのインスタンスを返す。
    # === ARGS
    # sheet:: 解析するシート
    # === RETURNS
    # 解析結果であるMonthDataのインスタンス
    def parse(sheet)
      @feature = EPCB::new_feature(@eutil) if @feature.nil?
      data_set = nil
      is_master = false # "マスタ"シートかどうかを表すフラグ
      # 正しいデータシートの場合
      if @eutil.is_valid_data_sheet_name(sheet.name)
        data_set = MonthData.new(sheet.name)
      # --masterが指定されていてマスタシートの場合
      elsif $options.master && EPCB::master_sheet?(sheet.name)
        data_set = MasterData.new
        is_master = true
      elsif $options.prefs && EPCB::prefs_sheet?(sheet.name)
        data_set = PreferencesData.new
        prefs_names = @feature.get_preferences_names()
        Log::debugln("prefs_names = #{prefs_names.inspect}")
        prefs_names.each do |name|
          value = @feature.get_preference(name)
          Log::debugln("prefs = { #{name} = #{value} }")
          data_set.store(name, value)
        end
        return data_set
      # その他、どうでもいいシートの場合
      else
        return nil
      end
      
      Log::voutln("Parsing sheet \"#{sheet.name}\"")
      sheet.activate
      @eutil.initialize_on_active_sheet
      # データ行を全て調べる
      for i in 0 .. @feature.const_of("MAX_DATA_LINE")
        # マスタシートの場合
        if is_master
          # cellsはCells(行, 列)
          value = sheet.cells(i + 1, 1).value
          # 3行以上空だったら処理を抜ける
          if value.nil?
            empty = true
            for j in 2 .. 3
              unless sheet.cells(i + j, 1).value.nil?
                empty = false
                break
              end
            end
            break if empty
            value = ""
          end
          data_set.use << UseMasterData.new(value)
        # 通常のデータシートの場合
        else
          break if @feature.is_empty_line_continued_to_limit(i)
          # 1行分のデータをサブクラスのメソッドで取得する。
          income_expenses_data = get_income_expenses_data(i)
          #puts "#{i} = #{income_expenses_data}"
          # data_setに対して1行分のデータを追加
          data_set.add(income_expenses_data)
        end
      end

      Log::voutln("Finished to parse sheet \"#{sheet.name}\"\n")
      return data_set
    end

    # Excelデータシートから1行分のデータを取得する。サブクラスでオーバライドする。
    # === ARGS
    # line:: 取得するデータの行オフセット
    # === RETURNS
    # Excelデータシートの1行分のデータを格納した配列
    def get_income_expenses_data(line) ; end
  end #ExcelParser#

  #
  # バージョン1.0用ExcelParser
  #
  class ExcelParser_1_0 < ExcelParser
    # "日付"、"用途"、"金額"を戻り値のデータに格納する。
    # "備考"には +nil+ が設定される。
    def get_income_expenses_data(line)
      # 日付
      date = @eutil.get_offset(line, @feature.const_of("DATE_OFFSET")).value
      # YYYY/MM/DDに変換
      date = ExcelUtil.to_yyyymmdd_format(date)

      # 用途
      use = @eutil.get_offset(line, @feature.const_of("USE_OFFSET")).value

      # 金額
      amount = @eutil.get_offset(line,
                                 @feature.const_of("AMOUNT_OF_MONEY_OFFSET")).value
      amount = amount.truncate if amount != nil
      return EPCB::new_specific_instance("IncomeExpensesData", @eutil, nil,
                                         date, use, amount)
    end
  end #ExcelParser_1_0#

  #
  # バージョン1.1用ExcelParser
  #
  class ExcelParser_1_1 < ExcelParser_1_0
    # 1.0のデータに加えて、ここでは"備考"も格納を戻り値のデータに格納する。
    def get_income_expenses_data(line)
      data = super(line)
      data.note = @eutil.get_offset(line,
                                    @feature.const_of("NOTE_OFFSET")).value
      return data
    end
  end #ExcelParser_1_1#

  #
  # バージョン1.2用ExcelParser。定義のみ。
  #
  class ExcelParser_1_2 < ExcelParser_1_1 ; end

end
