module Gitlab
  module Ci
    # This was inspired from: http://stackoverflow.com/a/10219411/1520132
    class TraceReader
      BUFFER_SIZE = 4096

      attr_accessor :path, :buffer_size

      def initialize(new_path, buffer_size: BUFFER_SIZE)
        self.path = new_path
        self.buffer_size = Integer(buffer_size)
      end

      def read(last_lines: nil)
        if last_lines
          read_last_lines(last_lines)
        else
          File.read(path)
        end
      end

      def read_last_lines(max_lines)
        File.open(path) do |file|
          chunks = []
          pos = lines = 0
          max = file.size

          # We want an extra line to make sure fist line has full contents
          while lines <= max_lines && pos < max
            pos += buffer_size

            buf = if pos <= max
                    file.seek(-pos, IO::SEEK_END)
                    file.read(buffer_size)
                  else # Reached the head, read only left
                    file.seek(0)
                    file.read(buffer_size - (pos - max))
                  end

            lines += buf.count("\n")
            chunks.unshift(buf)
          end

          chunks.join.lines.last(max_lines).join
            .force_encoding(Encoding.default_external)
        end
      end
    end
  end
end
