#!/usr/local/bin/ruby -w
# This software is in the public domain.  And stuff.

class StateIterator
	attr_reader :states
	def initialize(*states)
		@states = states
		@cur = 0
	end
	def current
		@states[@cur]
	end
	def advance!
		@cur = (@cur + 1) % @states.size
		current()
	end
end

class ConflictGrabber
	def initialize(io)
		@conflicts = []
		state = StateIterator.new(:open, :middle, :close)
		lineno = 0
		io.each_line {|line|
			case state.current
			when :open
				if line =~ /^<<<<<<</
					@conflicts.push([[], [], lineno + 1])
					state.advance!
				end
			when :middle
				if line =~ /^=======/
					@conflicts[-1].push(lineno + 2)
					state.advance!
				else
					@conflicts[-1][0].push(line)
				end
			when :close
				if line =~ /^>>>>>>>/
					state.advance!
				else
					@conflicts[-1][1].push(line)
				end
			end
			lineno += 1
		}
		if state.current != :open
			raise("unclosed state")
		end
		@conflicts.each {|ent|
			ent[0..-3].each {|part|
				part.each {|line|
					line.freeze
				}
				part.freeze
			}
			ent.freeze
		}
		@conflicts.freeze
	end
	attr_reader :conflicts
end

rcsid_regex = /(\$)([[:alnum:]\-_]+)(: [^ ]+,v [^$]+\$)/
ARGV.each {|fname|
	begin
		file = File.open(fname, 'r+')
		conflicts = ConflictGrabber.new(file)
	rescue
		printf("getting conflicts from %s: %s\n", fname, $!)
		next
	end

	found = false
	printf("RCSID conflict merging in %s: ", fname)
	conflicts.conflicts.each {|conflict|
		origmatches = conflict[0].collect {|line|
			rcsid_regex.match(line)
		}.compact
		next if origmatches.empty?
		origrepos = origmatches.collect {|m| m[2]}
		next if origrepos.uniq.size < origrepos.size

		newmatches = conflict[1].collect {|line|
			rcsid_regex.match(line)
		}.compact
		newrepos = newmatches.collect {|m| m[2]}

		common_repos = origrepos & newrepos
		next if common_repos.size != 1
		common_repo = common_repos[0]
		printf("common found (%s)\n\n", common_repo)

		newlines = found = conflict[0].collect {|line|
			if rcsid_regex =~ line && $2 == common_repo
				line.sub(rcsid_regex) {
					$1 + $2 + newmatches.find {|m| m[2] == common_repo}[3]
				}
			else
				line
			end
		}
		puts("Would you like to replace the conflict")
		file.rewind
		flines = file.readlines
		firstline = conflict[2] - 1
		lastline = conflict[3] + conflict[1].size - 1
		puts(flines[firstline..lastline].collect {|line| "\t".concat(line)})
		puts("\nwith the lines\n")
		puts(newlines.collect {|line| "\t".concat(line)})
		print("\n? [y/N] ")
		$stdout.flush
		line = $stdin.gets
		if line && line.length >= 1 && line[0, 1].downcase == "y"
			file.rewind
			wlen = file.write((flines[0...firstline] + newlines +
			  flines[lastline + 1..-1]).join)
			file.flush
			file.truncate(wlen)
		end
	}
	if !found
		puts("none found")
	end
}
