# encoding: UTF-8
#
# Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

require 'csv'
require 'fileutils'

module GoodData
  module Helpers
    class Csv
      class << self
        # Read data from CSV
        #
        # @param [Hash] opts
        # @option opts [String] :path File to read data from
        # @option opts [Boolean] :header File to read data from
        # @return Array of rows with loaded data
        def read(opts)
          path = opts[:path]
          res = []

          line = 0

          CSV.foreach(path) do |row|
            line += 1
            next if opts[:header] && line == 1

            if block_given?
              data = yield row
            else
              data = row
            end

            res << data if data
          end

          res
        end

        # Read data from csv as an array of hashes with symbol keys and parsed integers
        # @option filename String
        def read_as_hash(filename)
          res = []
          return res unless File.exist? filename

          CSV.parse(File.read(filename), headers: true, header_converters: :symbol, converters: :integer).map do |row|
            res << row.to_hash
          end
          res
        end

        # Write data to CSV
        # @option opts [String] :path File to write data to
        # @option opts [Array] :data Mandatory array of data to write
        # @option opts [String] :header Optional Header row
        def write(opts, &_block)
          path = opts[:path]
          header = opts[:header]
          data = opts[:data]

          CSV.open(path, 'w') do |csv|
            csv << header unless header.nil?
            data.each do |entry|
              res = yield entry
              csv << res if res
            end
          end
        end

        # Ammend a hash to CSV in a smart manner
        # @option filename String
        # @option data Hash
        def ammend_line(filename, data)
          current_data = read_as_hash(filename)
          data_to_write = (current_data << data).map(&:sort).map { |r| Hash[r] }
          FileUtils.mkpath(filename.split('/')[0...-1].join('/'))
          CSV.open(filename, 'w', write_headers: true, headers: data_to_write.first.keys) do |csv|
            data_to_write.each do |d|
              csv << d.values
            end
          end
        end
      end
    end
  end
end