# encoding: UTF-8
require "csv"

class CsvExporter
  attr_accessor :collection, :columns, :opts

  def initialize(collection, columns, opts = {})
    @collection = collection
    @opts = opts
    @opts[:encoding] ||= 'ISO-8859-1'
    @columns = secure_encode(columns)
  end

  def generate(&block)
    CSV.generate(:col_sep => ";", :force_quotes => true) do |csv|
      csv << columns

      @collection.find_each do |record|
        csv << secure_encode(filter_record(record, &block))
      end
    end
  end

  def export(&block)
    filename = @opts[:file_name].try(:gsub, /\.csv/, '') || 'export'

    csv_file = if @opts[:save_path]
                 File.new(File.join(@opts[:save_path], "#{filename}.csv"), 'w')
               else
                 Tempfile.new(["#{filename}-", '.csv'], File.join(Rails.root, 'tmp'))
               end

    CSV.open(csv_file, 'wb', :col_sep => ";", :force_quotes => true) do |csv|
      csv << columns

      loop_method = @collection.respond_to?(:find_each) ? :find_each : :each
      @collection.send(loop_method) do |record|
        csv << secure_encode(filter_record(record, &block))
      end
    end

    csv_file
  end

  private

  def filter_record(record, &block)
    if block_given?
      block.call(record)
    else
      @opts[:values].map { |value| record.try(value) }
    end
  end

  def secure_encode(row)
    row.map do |col|
      col.to_s.encode(@opts[:encoding], :invalid => :replace, :undef => :replace) if col
    end
  end
end
