require_relative '../filelogger'
require_relative '../dataset_utils'

class Index
  include Singleton
  def initialize()
    @index = 0
  end
  def increase()
    @index = @index + 1
  end
  def get()
    return @index
  end
end

module Embulk
  module Parser

    class BinaryParserPlugin < ParserPlugin
      Plugin.register_parser("binary", self)

      METADATA_FILE_NAME = "/.metadata_file"

      def self.transaction(config, &control)
	tool_dir = config.param('tool_dir', :string, default: ".")
	@logger = LogManager.instance()
	@logger.setFilename(tool_dir, "ingestion")
	task = {
	  chunk_size: config.param('chunk_size', :float, default: 0) * DatasetUtils::MEGA,
	  supplier: config.param("supplier", :string, default: "parser"),
	  data_set: config.param("data_set", :string),
	  input_plugin: config.param("storage", :string, default: "parser"),
	  date: Time.now.strftime("%Y-%m-%d_%H-%M-%S")
	}
	if task['chunk_size'] == 0
	  task['chunk_size'] = DatasetUtils::CHUNK_SIZE
	end
	columns = [
	    Column.new(0, "supplier", :string),
	    Column.new(1, "data_set", :string),
	    Column.new(2, "file", :string),
	    Column.new(3, "extension", :string),
	    Column.new(4, "data_chunk", :string),
	    Column.new(5, "eof", :string),
	    Column.new(6, "size", :string),
	    Column.new(7, "hash", :string)
	  ]

	yield(task, columns)
      end

      def run(file_input)
	@index = Index.instance().get()
	@logger = LogManager.instance()
	while file = file_input.next_file
	  begin
	    metadata_file = Dir.pwd + METADATA_FILE_NAME
	    metadata = File.open(metadata_file) {|f| f.readline} if File.exist?(metadata_file)
	    File.delete(metadata_file) if File.exist?(metadata_file)
	  rescue Exception => e
	    @logger.error("An error occurred while getting file metadata: " + e.to_s)
	    @logger.error(e.backtrace)
	  end
	  begin
	    if metadata
	      extension = File.extname metadata
	      filename = metadata.reverse.sub(extension.reverse, "").reverse
	      extension.gsub! '.', ''
	      extension = extension == "" ? DatasetUtils::NONE_EXT : extension
	    else
	      filename = "file_from_#{task['input_plugin']}_#{task['date']}"
	      extension = @index.to_s.rjust(3, "0")
	    end
	    each_chunk(file, filename.chomp, extension.chomp, task['chunk_size']) do |record|
	      @page_builder.add(record)
	    end
	    @page_builder.finish
	    Index.instance().increase()
	  rescue java.lang.OutOfMemoryError
	    @logger.logOutOfMemoryError(path)
	    @logger.abortExecution()
	  rescue Exception => e
	    @logger.error("An error occurred during file ingestion: " + e.to_s, print=TRUE)
	    @logger.error(e.backtrace)
	    puts "[INFO] For more detailed information, please refer to the log file: " + @logger.getLogPath()
	  end
	end
      end

      private
      def each_chunk(file, filename, extension, chunk_size=DatasetUtils::CHUNK_SIZE)
	npart = 0
	next_byte = file.read(1)
	first = TRUE
	while true
	    data = next_byte
	    if not next_byte
		if first
		  # this means this is an empty file
		  values = [task['supplier'], task['data_set'], filename, extension, "", "", "", ""]
		  yield(values)
		end
		break
	    end
	    data += file.read(chunk_size)
	    next_byte = file.read(1)
	    if not next_byte
		eof = DatasetUtils::EOF
		if first
		  # this means that the whole file will be ingested at once (not split)
		  eof = ""
		end
	    else
		npart += 1
       	 	eof = npart.to_s.rjust(3, "0")
	    end
	    content = Base64.encode64(data)
	    values = [task['supplier'], task['data_set'], filename, extension, content, eof, "", ""]
	    first = FALSE
	    yield(values)
	end
      end

    end
  end
end
