# Grab given fish histories and merge them in time order. The format of the
# history is simple:
#
#  # <time in seconds from epoch>
#  <cmdline>
#  [...]

# Struct representing one history element. It contains a time (number of
# seconds since epoch) and the command as a string.
class FishHistoryElement
  attr_accessor :epoch, :cmd

  def initialize( epoch, cmd )
    @epoch = epoch
    @cmd = cmd
  end

  # Return string in the history file format of fish. Make sure that there is
  # one newline (\n) at the end of the command.
  def to_s
    cmd = @cmd[-1..-1]=="\n" ? @cmd : @cmd + "\n"
    "# #{@epoch}\n#{cmd}"
  end
end


# Class to represent a shell (fish) history. Should be able to merge histories
# and remove douplicates.
class FishHistory
  # Parse the contents of string, returning an array of FishHistoryElements
  # corresponding to the string.
  def self.parse_str( str )
    hist_ary = []
    matches = str.scan( /#\s*(\d+)\s*\n((.*\\\n)*(.*$)?)/ )
    matches.map do |match|
      FishHistoryElement.new( match[0].to_i, match[1] )
    end
  end

  # Merge the arrays of FishHistoryElements into a new array. Duplicates
  # are removed, the newest (most seconds since epoch) is retained. The final
  # array is sorted by ascending times.
  def self.merge( *arrays )
    element_hash = {}
    arrays.each do |ary|
      ary.each do |elem|
        if !element_hash.has_key?( elem.cmd ) or ( element_hash[ elem.cmd ].epoch < elem.epoch )
          element_hash[ elem.cmd ] = elem
        end
      end
    end

    element_hash.values.sort{ |a,b| a.epoch <=> b.epoch }
  end

  # Initialize local history variable
  def initialize
    @history_list = []
  end

  # Import str into local history list, by parsing and merging the resulting array.
  def import_string( str )
    history_list = FishHistory.parse_str( str )
    @history_list = FishHistory.merge( @history_list, history_list )
  end

  # Return string representation of history as found in a file.
  def to_s
    @history_list.to_s
  end
end

# Just take all arguments and merge them.
def main
  fnames = ARGV

  fish_history = FishHistory.new

  # FIXME: We have loads of memory and we don't care about speed. Really, it
  # probably is not worth optimizing this.
  fnames.each do |fname|
    fish_history.import_string( File.read( fname ) )
  end

  print fish_history
end

if $0 == __FILE__
  main
end
