#
# == epcb/csv/all-generator
# 古いExcelPettyCashBookから新しいExcelPettyCashBookを出力する機能を提供する。
#
# Revision:: $Id$
#
require 'fileutils'
require 'epcb/excel-parser'
require 'epcb/excel-serializer'
require 'epcb/csv/common'
require 'epcb/csv/csv-serializer'
require 'epcb/csv/csv-parser'

module EPCB::CSV
  #
  # ExcelPettyCashBookからCSVファイルを生成するGenerator。
  #
  class CSVGenerator < Generator
    # 読み込むファイルと出力するファイルを決定する。
    # +dest_file+が nil の場合は+src_file+から出力先のパスを決定する。
    # === ARGS
    # src_file:: 読み込むExcelPettyCashBookファイル
    # dest_file:: 出力するCSVファイル
    def setup(src_file, dest_file = nil)
      super(src_file, dest_file)

      if dest_file.nil?
        # ソースファイルから出力先ファイル名を決める
        name = File.basename(src_file, ".*")
        @dest_path = File.file_system.getAbsolutePathName("#{name}.csv")
        Log::voutln("dest_path = #{@dest_path}")
      end
    end

    # ExcelPettyCashBookのデータを吸い上げて、CSVファイルに出力する。
    def execute
      workbook = @eutil.open_workbook_and_activate(@src_path)
      @parser = EPCB::new_specific_instance("ExcelParser",
                                            @eutil, nil, @eutil)
      File.open(@dest_path, "wb") do |dest_file|
        @serializer = CSVSerializer.new(dest_file)
        # Excelのシートを全部調べる
        for i in 1 .. workbook.worksheets.count
          sheet = workbook.worksheets(i)
          data_set = @parser.parse(sheet)
          @serializer.serialize(data_set) unless data_set.nil?
        end
      end
    end
  end #CSVGenerator#

  #
  # CSVからデータを吸い上げてExcelPettyCashBookを出力するGenerator。
  #
  class ExcelGenerator < Generator
    def initialize
      super()
      @template_path = nil
    end

    # 読み込むファイルと出力するファイルを決定する。
    # dest_fileがnilの場合はsrc_fileから出力先のパスを決定する。
    # また、オプションの--templateが指定されているかもチェックする。
    #
    # === ARGS
    # src_file:: 読み込むExcelPettyCashBookファイル
    # dest_file:: 出力するCSVファイル
    def setup(src_file, dest_file = nil)
      super(src_file, dest_file)
      if $options.template.nil?
        raise(EPCB::OptionUnsatisfiedError,
              "specify --template option" \
              " for subcommand \"#{EPCB::SUBC_EXCEL}\" or \"#{EPCB::SUBC_ALL}\".")
      end
      ::CLI::ensure_file_exist($options.template)
      @template_path = File.file_system.getAbsolutePathName($options.template)

      if dest_file.nil?
        # ソースファイルから出力先ファイルを決める
        # パス名規則: <カレントディレクトリ>/_<数値>_<ソースファイル名>.xls
        prefix = "#{Dir::pwd}/_"
        for i in 1 .. 50000
          path = "#{prefix}#{i.to_s}_#{File.basename(@src_path, ".*")}.xls"
          Log::voutln("Created path = #{path}")
          break unless FileTest.exist?(path)
        end
        @dest_path = File.file_system.getAbsolutePathName(path)
        Log::voutln("dest_path = #{@dest_path}")
      end
      Log::voutln("template_path = #{@template_path}")
      FileUtils.cp(@template_path, @dest_path, :verbose => $options.verbose)
    end
    
    # CSVファイルのデータを吸い上げて、ExcelPettyCashBookに出力する。
    def execute
      super()
      Log::voutln

      workbook = @eutil.open_workbook_and_activate(@dest_path)
      @serializer = ::EPCB::ExcelSerializer.new(workbook, @eutil)
      @parser = CSVParser.new(@src_path)
      while @parser.has_next_line?
        data_set = @parser.parse
        Log::voutln("Finished to parse sheet \"#{data_set.name}\".\n")
        @serializer.serialize(data_set)
      end

      # 全データシートのデータを計算
      @eutil.excel.run("CalculateAllForEverySheet")
      workbook.save
    end
  end #ExcelGenerator#

  #
  # 古いExcelPettyCashBookからCSVデータを生成して、
  # 新しいExcelPettyCashBookにデータを移行するクラス。
  #
  class CSVAndExcelGenerator < Generator
    def initialize
      super()
      @csv_generator = CSVGenerator.new
      @excel_generator = ExcelGenerator.new
    end

    def setup(src_file, dest_file = nil)
      @csv_generator.setup(src_file, nil)
      csv_path = @csv_generator.dest_path
      # csv_pathのファイルがない場合、ExcelGenerator#setupでエラーになるので、
      # 空のファイルを作成しておく
      FileUtils.touch(csv_path, :verbose => $options.verbose)
      @excel_generator.setup(csv_path, dest_file)
    end

    def execute
      begin
        @csv_generator.execute
      ensure
        @csv_generator.destroy
      end
      @excel_generator.execute
    end

    def destroy
      super()
      begin
        @csv_generator.destroy
        @excel_generator.destroy
      ensure
        if @csv_generator.dest_path != nil \
          && FileTest.exist?(@csv_generator.dest_path) \
          && !$options.leave
          # CSVファイルを削除
          FileUtils.rm(@csv_generator.dest_path,
                       :force => true, :verbose => $options.verbose)
        end
      end
    end
  end #CSVAndExcelGenerator#
end
