-- Compare items in two sequences to find a longest common subsequence.
-- Given lengths of sequences and input function to compare items at indexes,
-- return by output function the number of adjacent items and starting indexes
-- of each common subsequence.

return function(aLength: number, bLength: number, isCommon: IsCommon, foundSubsequence: FoundSubsequence): ()
	validateLength("aLength", aLength)
	validateLength("bLength", bLength)
	validateCallback("isCommon", isCommon)
	validateCallback("foundSubsequence", foundSubsequence)

	-- Count common items from the start in the forward direction.
	local nCommonF = countCommonItemsF(0, aLength, 0, bLength, isCommon)

	if nCommonF ~= 0 then
		foundSubsequence(nCommonF, 0, 0)
	end

	-- Unless both sequences consist of common items only,
	-- find common items in the half-trimmed index intervals.
	if aLength ~= nCommonF or bLength ~= nCommonF then
		-- Invariant: intervals do not have common items at the start.
		-- The start of an index interval is closed like array slice method.
		local aStart = nCommonF
		local bStart = nCommonF

		-- Count common items from the end in the reverse direction.
		local nCommonR = countCommonItemsR(aStart, aLength - 1, bStart, bLength - 1, isCommon)

		-- Invariant: intervals do not have common items at the end.
		-- The end of an index interval is open like array slice method.
		local aEnd = aLength - nCommonR
		local bEnd = bLength - nCommonR

		-- Unless one sequence consists of common items only,
		-- therefore the other trimmed index interval consists of changes only,
		-- find common items in the trimmed index intervals.
		local nCommonFR = nCommonF + nCommonR
		if aLength ~= nCommonFR and bLength ~= nCommonFR then
			local nChange = 0 -- number of change items is not yet known
			local transposed = false -- call the original unwrapped functions
			local callbacks = { { foundSubsequence, isCommon } }

			-- Indexes in sequence a of last points in furthest reaching paths
			-- from outside the start at top left in the forward direction:
			local aIndexesF = { NOT_YET_SET }
			-- from the end at bottom right in the reverse direction:
			local aIndexesR = { NOT_YET_SET }

			-- Initialize one object as output of all calls to divide function.
			local division = {
				aCommonFollowing = NOT_YET_SET,
				aCommonPreceding = NOT_YET_SET,
				aEndPreceding = NOT_YET_SET,
				aStartFollowing = NOT_YET_SET,
				bCommonFollowing = NOT_YET_SET,
				bCommonPreceding = NOT_YET_SET,
				bEndPreceding = NOT_YET_SET,
				bStartFollowing = NOT_YET_SET,
				nChangeFollowing = NOT_YET_SET,
				nChangePreceding = NOT_YET_SET,
				nCommonFollowing = NOT_YET_SET,
				nCommonPreceding = NOT_YET_SET,
			}

			-- Find and return common subsequences in the trimmed index intervals.
			findSubsequences(nChange, aStart, aEnd, bStart, bEnd, transposed, callbacks, aIndexesF, aIndexesR, division)
		end

		if nCommonR ~= 0 then
			foundSubsequence(nCommonR, aEnd, bEnd)
		end
	end
end
