Find Duplicate Place Names.fh_lua

--[[
@Title:			Find Duplicate Place Names
@Type:				Standard
@Author:			Mike Tate
@Version:			1.0
@Keywords:		
@LastUpdated:	25 Apr 2022
@Licence:			This plugin is copyright (c) 2022 Mike Tate and contributors, and is licensed under the MIT License which is hereby incorporated by reference (see https://pluginstore.family-historian.co.uk/fh-plugin-licence)
@Description:	List any Place records whose tidied names would be duplicates and thus should be merged. Variations due to placement of commas and spaces, or the case of letters are disregarded.
]]

local strVersion = "1.0"

function Main()
	local arrTidyTxt = {}
	local arrTidyRec = {}
	local arrTidyRid = {}
	local arrCopyRec = {}
	local arrCopyRid = {}
	local dicRec = {}
	local ptrRec = fhNewItemPtr()							-- See Sample Plugin Scripts ~ Surname Summary loop
	ptrRec:MoveToFirstRecord("_PLAC")
	while ptrRec:IsNotNull() do
		local strText = fhGetItemText(ptrRec,"~.TEXT")
		local strTidy = fhCallBuiltInFunction("TextPart",strText,1,0,"TIDY"):gsub(" +([ ,])","%1")	-- gsub fixes TextPart bug
		local ptrTidy = dicRec[strTidy:lower()]			-- Need lower() to cater for case variants
		if ptrTidy then											-- Duplicate tidied name found so save Result Set data of both records
			table.insert(arrTidyTxt,strTidy)
			table.insert(arrTidyRec,ptrTidy:Clone())
			table.insert(arrTidyRid,fhGetRecordId(ptrTidy))
			table.insert(arrCopyRec,ptrRec:Clone())
			table.insert(arrCopyRid,fhGetRecordId(ptrRec))
		else
			dicRec[strTidy:lower()] = ptrRec:Clone()		-- Save pointer to Place record against tidied name -- Need lower() to cater for case variants
		end
		ptrRec:MoveNext() 
	end
	if #arrTidyRec > 0 then
		fhOutputResultSetTitles( "Find Duplicate Place Names  "..strVersion )
		fhOutputResultSetColumn( "Tidy Place Name", "text", arrTidyTxt, #arrTidyRec, 200, "align_left" )
		fhOutputResultSetColumn( "Original Record", "item", arrTidyRec, #arrTidyRec, 200, "align_left" )
		fhOutputResultSetColumn( "Rec Id",       "integer", arrTidyRid, #arrTidyRec,  30, "align_right")
		fhOutputResultSetColumn( "Duplicate Record","item", arrCopyRec, #arrTidyRec, 200, "align_left" )
		fhOutputResultSetColumn( "Rec Id",       "integer", arrCopyRid, #arrTidyRec,  30, "align_right")
--		fhMessageBox("\n" .. tostring(#arrTidyRec) .. " duplicate place names found\n")
	else
		fhMessageBox("\n No duplicate place names found \n")
	end
end -- function Main

--[[
@Function:		CheckVersionInStore
@Author:			Mike Tate
@Version:			1.2
@LastUpdated:	10 Jul 2021
@Description:	Check plugin version against version in Plugin Store
@Parameter:		Plugin name and version
@Returns:			None
@Requires:		lfs & luacom
@V1.2:				Ensure the Plugin Data folder exists;
@V1.1:				Monthly interval between checks; Report if Internet is inaccessible;
@V1.0:				Initial version;
]]

function CheckVersionInStore(strPlugin,strVersion)							-- Check if later Version available in Plugin Store

	require "lfs"
	require "luacom"

	local function OpenFile(strFileName,strMode)								-- Open File and return Handle
		local fileHandle, strError = io.open(strFileName,strMode)
		if fileHandle == nil then
			error("\n Unable to open file in \""..strMode.."\" mode. \n "..strFileName.." \n "..strError.." \n")
		end
		return fileHandle
	end -- local function OpenFile

	local function SaveStringToFile(strString,strFileName)					-- Save string to file
		local fileHandle = OpenFile(strFileName,"w")
		fileHandle:write(strString)
		assert(fileHandle:close())
	end -- local function SaveStringToFile

	local function httpRequest(strRequest)										-- Luacom http request protected by pcall() below
		local http = luacom.CreateObject("winhttp.winhttprequest.5.1")
		http:Open("GET",strRequest,false)
		http:Send()
		return http.Responsebody
	end -- local function httpRequest

	local function intVersion(strVersion)										-- Convert version string to comparable integer
		local intVersion = 0
		local arrNumbers = {}
		strVersion:gsub("(%d+)", function(strDigits) table.insert(arrNumbers,strDigits) end)
		for i = 1, 4 do
			intVersion = intVersion * 1000 + tonumber(arrNumbers[i] or 0)
		end
		return intVersion
	end -- local function intVersion

	local strLatest = "0"
	if strPlugin then
		local strPath = fhGetContextInfo("CI_APP_DATA_FOLDER").."\\Plugin Data\\"
		local strFile = strPath.."VersionInStore "..strPlugin..".dat"
		local intTime = os.time() - 2600000 									-- Time in seconds a month ago
		local tblAttr, strError = lfs.attributes(strFile)					-- Obtain file attributes
		if not tblAttr or tblAttr.modification < intTime then				-- File does not exist or was modified long ago 
			if lfs.attributes(strPath,"mode") ~= "directory" then
				if not lfs.mkdir(strPath) then return end 					-- Ensure the Plugin Data folder exists
			end
			SaveStringToFile(strFile,strFile)									-- Update file modified time
			local strFile = strPath.."VersionInStoreInternetError.dat"
			local strRequest ="http://www.family-historian.co.uk/lnk/checkpluginversion.php?name="..tostring(strPlugin)
			local isOK, strReturn = pcall(httpRequest,strRequest)
			if not isOK then														-- Problem with Internet access
				local intTime = os.time() - 36000								-- Time in seconds 10 hours ago
				local tblAttr, strError = lfs.attributes(strFile)			-- Obtain file attributes
				if not tblAttr or tblAttr.modification < intTime then		-- File does not exist or was modified long ago 
					fhMessageBox(strReturn.."\n The Internet appears to be inaccessible. ")
				end
				SaveStringToFile(strFile,strFile)								-- Update file modified time
			else
				os.remove(strFile)													-- Delete file if Internet is OK
				if strReturn then
					strLatest = strReturn:match("([%d%.]*),%d*")				-- Version digits & dots then comma and Id digits 
				end
			end
		end
	end
	if intVersion(strLatest) > intVersion(strVersion or "0") then
		fhMessageBox("Later Version "..strLatest.." of this Plugin is available from the Plugin Store.")
	end
end -- function CheckVersionInStore

fhInitialise(6,0,0,"save_recommended")

CheckVersionInStore("Find Duplicate Place Names",strVersion)

Main()

Source:Find-Duplicate-Place-Names.fh_lua