Add GRO Index Source Citation.fh_lua

--[[
@Title:			Add GRO Index Source Citation
@Type:				Standard
@Author:			Mike Tate
@Contributors:	Jane Taubman
@Version:			1.0
@Keywords:		
@LastUpdated:	26 May 2023
@Licence:			This plugin is copyright (c) 2023 Mike Tate & 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:	Add a GRO Index Source Citation to an Event and optionally create the event and or set the fields.
					Records the Selected Source in a Parameter file for each Project. If run without a project the source record will need to be selected each time.
@V1.0:				Derived from Add GRO Source V1.3 with options for selecting Source Records, for Where within Source v Text From Source v Event Note Only, mode of Entry Date, mode of Event date, and adding citation to Names
]]

Version = "1.0"

require("iuplua")
if fhGetAppVersion() > 5 then
	fhSetStringEncoding("UTF-8")
	iup.SetGlobal("UTF8MODE","YES")
	iup.SetGlobal("UTF8MODE_FILE","NO")
	iup.SetGlobal("CUSTOMQUITMESSAGE","YES")					-- Needed for IUP 3.28
end

function doError(strMessage)
	error("\n\n "..strMessage.." - Plugin Aborted.\n\n")
end -- function doError

function addParam( arrParams, strText, strType, strTip )
	table.insert( arrParams, strText..strType.."{"..(strTip or "").."}" )
end -- function addParam

function main()

	-- Set Lookup Tables and Prompt Dialogue
	local arrEvents = { "BIRT"; "MARR"; "DEAT"; }
	local arrGROType= { "Birth"; "Marriage"; "Death"; }
	local arrShortP = {"Q1";"Q2";"Q3";"Q4";"Jan";"Feb";"Mar";"Apr";"May";"Jun";"Jul";"Aug";"Sep";"Oct";"Nov";"Dec";}
	local arrPeriod = {"Q1 Jan-Feb-Mar";"Q2 Apr-May-Jun";"Q3 Jul-Aug-Sep";"Q4 Oct-Nov-Dec";"January";"February";"March";"April";"May";"June";"July";"August";"September";"October";"November";"December";}
	local strPeriod = table.concat(arrPeriod,"|")
	local strIfDate = "|No Event Date|Year Only Event Date|Inexact Event Date|"
	local strFields = "|Where within Source|Text From Source|Event Note Only|"
	local strAssess = "|None |Unreliable |Questionable |Secondary Evidence  |Primary Evidence  |"
	local tblAssess = { "Unreliable"; "Questionable"; "Secondary Evidence"; "Primary Evidence"; ""; }
	local arrParams = { "%t" }
	addParam( arrParams, "GRO Index Type:"                        , "%l|  Birth  |  Marriage  |  Death  |"         , "Type of GRO Index Event" )
	addParam( arrParams, "Registration Year:"                     , "%i"                                           , "Registration Year for the Event" )
	addParam( arrParams, "Registration Quarter or Month:"         , "%l|"..strPeriod.."|"                          , "Registration Quarter or Month"   )
	addParam( arrParams, "Registration District:"                 , "%s"                                           , "Registration District Placename" )
	addParam( arrParams, "GRO Index Reference && Names:"          , "%s"                                           , "GRO Index Volume, Page & Names"  )
	addParam( arrParams, "Mothers Maiden Name (Birth only):"      , "%s"                                           , "Applies to GRO Birth Index only" )
	addParam( arrParams, "Recorded Age at Death (Death only):"    , "%s"                                           , "Applies to GRO Death Index only" )
	addParam( arrParams, "Put GRO Index Date in Event Date when:" , "%l"..strIfDate                                , "Overwrite Event Date Criteria"   )
	addParam( arrParams, "Select Citation Reference Field:"       , "%l"..strFields                                , "Which Citation Field for References?" )
	addParam( arrParams, "If 'Event Note Only' selected, ignore settings below" , "%t" )
	addParam( arrParams, "Birth Source Record Id:"                , "%i"                                           , "GRO Birth Index Source Record Id"    )
	addParam( arrParams, "Marriage Source Record Id:"             , "%i"                                           , "GRO Marriage Index Source Record Id" )
	addParam( arrParams, "Death Source Record Id:"                , "%i"                                           , "GRO Death Index Source Record Id"    )
	addParam( arrParams, "Set Citation Entry Date:"               , "%l|No Date|Today's Date|GRO Index Reg Date |" , "Citation Entry Date" )
	addParam( arrParams, "Set Citation Assessment:"               , "%l"..strAssess                                , "Citation Assessment" )
	addParam( arrParams, "Add Citation to Name:"                  , "%b[  No ,  Yes ]"                             , "Add Citation to Name of Person/Spouses?" )
	local strParams = table.concat(arrParams,"\n").."\n"

	-- Set Parameter Default Values
	local intPtype = 0			-- GRO Index Event Type
	local intPyear = 1800		-- Registration Year
	local intPquat = 0			-- Registration Quarter or Month
	local strPdist = ""			-- Registration District
	local strPrefn = ""			-- GRO Index Reference
	local strPmaid = ""			-- Mothers Maiden Name
	local strPaged = ""			-- Age at Death
	local intPeven = 0			-- Overwrite Event Date Criteria
	local intPcite = 0			-- Select Citation Field for Ref
	local intPbirt = nil		-- Source Record Id Birth
	local intPmarr = nil		-- Source Record Id Marriage
	local intPdeat = nil		-- Source Record Id Death
	local intPdate = 0			-- Select Citation Entry Date
	local intPqual = 0			-- Select Citation Assessment
	local intPname = 0			-- Add Citation to Name?

	-- Get Parameters from Previous Sticky Data
	local strParamFile = fhGetPluginDataFileName()
	local strChunk = fhLoadTextFile(strParamFile)
	if strChunk then
		local doChunk = load(strChunk)
		intPeven, intPcite, intPbirt, intPmarr, intPdeat, intPdate, intPqual, intPname = doChunk()
	end

	-- Otherwise Select Source Records
	if intPbirt == nil then
		local strAns = "Retry"
		while strAns == "Retry" do
			strAns = ""
			fhMessageBox("\n Please select just one generic GRO Index source record. \n                        ALTERNATIVELY \n Select 3 source records for Birth, Marriage, and Death, \n ensuring they are in that order in the righthand pane. \n","MB_OK","MB_ICONINFORMATION")
			-- Get Source Records to use.
			local ptrList = fhPromptUserForRecordSel("SOUR",3)
			if #ptrList == 0 then
				strAns = fhMessageBox("\n No source records have been selected ...\n\n   Click  'Abort'  to cancel the plugin\n   Click  'Retry'    to select the sources again\n   Click  'Ignore'  to continue without sources \n","MB_ABORTRETRYIGNORE","MB_ICONQUESTION")
				if strAns == "Abort" then return end
				intPbirt = 0
				intPmarr = 0
				intPdeat = 0
			elseif #ptrList == 1 then
				intPbirt = fhGetRecordId(ptrList[1])
				intPmarr = fhGetRecordId(ptrList[1])
				intPdeat = fhGetRecordId(ptrList[1])
			elseif #ptrList == 2 then
				strAns = fhMessageBox("\n Only two source records were selected ...\n\n   Click  'Retry'    to select the sources again \n   Click  'Cancel'  to cancel the plugin \n","MB_RETRYCANCEL","MB_ICONQUESTION")
				if strAns == "Cancel" then return end
			else --#ptrList == 3 then
				intPbirt = fhGetRecordId(ptrList[1])
				intPmarr = fhGetRecordId(ptrList[2])
				intPdeat = fhGetRecordId(ptrList[3])
			end
		end
	end

	-- Get Current Individual Record if Available
	local ptrList = fhGetCurrentRecordSel("INDI")
	if #ptrList == 1 then
		strName = "Current Record: "..fhGetItemText(ptrList[1],"~.NAME"):gsub("%%","%%%%").." ("..fhCallBuiltInFunction("LifeDates",ptrList[1])..")"
	else
		strName = "No record selected"
	end

	-- Get GRO Information Parameters
	local isOK
	isOK,	intPtype, intPyear, intPquat, strPdist, strPrefn, strPmaid, strPaged, intPeven, intPcite, intPbirt, intPmarr, intPdeat, intPdate, intPqual, intPname = iup.GetParam("Add GRO Index Source Citation "..Version, param_action, strName..strParams,
			intPtype, intPyear, intPquat, strPdist, strPrefn, strPmaid, strPaged, intPeven, intPcite, intPbirt, intPmarr, intPdeat, intPdate, intPqual, intPname )
	-- Check for Cancel
	if not isOK then return end

	-- Save Sticky Parameters
	if fhGetContextInfo("CI_APP_MODE") == "Project Mode" then
		local strParams = "return "..intPeven..","..intPcite..","..intPbirt..","..intPmarr..","..intPdeat..","..intPdate..","..intPqual..","..intPname.."\n"
		fhSaveTextFile(strParamFile, strParams, "UTF-8")
	end

	-- Select Source Record
	local intSource = 0
	local intEvent = intPtype + 1
	if intEvent == 1 then intSource = intPbirt end
	if intEvent == 2 then intSource = intPmarr end
	if intEvent == 3 then intSource = intPdeat end
	local ptrSource = fhNewItemPtr()
	ptrSource:MoveToRecordById("SOUR",intSource)
	if ptrSource:IsNull() then
		doError("Source Record Id "..intSource.." Not Found")
	end

	-- Obtain Desired Record
	if intPtype == 1 then
		ptrList = fhGetCurrentRecordSel("FAM")
		if #ptrList == 0 then
			ptrList = fhGetCurrentRecordSel("INDI")
			if #ptrList == 1 then
				ptrList = getSpouseFamilies(ptrList[1])
			end
		end
		if #ptrList ~= 1 then
			ptrList = fhPromptUserForRecordSel("FAM",1)
		end
	else
		ptrList = fhGetCurrentRecordSel("INDI")
		if #ptrList ~= 1 then
			ptrList = fhPromptUserForRecordSel("INDI",1)
		end
	end
	if #ptrList == 0 then
		doError("No Principal Record Selected")
	end

	-- Check Registration Year
	if intPyear <= 1800 then
		doError("Registration Year before 1800")
	end

	-- Event Note Only inhibits Citation options
	if intPcite == 2 then
		intPdate = 0
		intPqual = 0
		intPname = 0
	end

	local ptrEvent = fhNewItemPtr()
	local ptrField = fhNewItemPtr()
	ptrEvent:MoveTo(ptrList[1],"~."..arrEvents[intEvent])
	if ptrEvent:IsNull() then
		-- Create Event
		ptrEvent = fhCreateItem(arrEvents[intEvent],ptrList[1])
	end

	-- Set Event Date
	ptrField:MoveTo(ptrEvent,"~.DATE")
	if ptrField:IsNull() then
		ptrField = fhCreateItem("DATE",ptrEvent)
	end
	local dtDate = fhGetValueAsDate(ptrField)
	local dpOne = dtDate:GetDatePt1()
	local dpTwo = dtDate:GetDatePt2()
	local Month = dpOne:GetMonth()
	local DayNo = dpOne:GetDay()
	if intPeven >= 0 and dpOne:IsNull()        and dpTwo:IsNull()
	or intPeven >= 1 and dpOne:GetMonth() == 0 and dpTwo:GetMonth() == 0
	or intPeven >= 2 and dpOne:GetDay()   == 0 and dpTwo:GetDay()   == 0
	then
		dtDate:SetValueAsText(arrShortP[intPquat + 1].." "..intPyear)
		fhSetValueAsDate(ptrField,dtDate)
	end

	-- Set Event Place & Address
	strPdist = promptPlace(strPdist)
	ptrField:MoveTo(ptrEvent,"~.PLAC")
	if ptrField:IsNull() then
		ptrField = fhCreateItem("PLAC",ptrEvent)
	end
	if fhGetValueAsText(ptrField) == "" then
		fhSetValueAsText(ptrField,strPdist)
		-- If Place was added, add "Registration District" as the Address field
		ptrField:MoveTo(ptrEvent,"~.ADDR")
		if ptrField:IsNull() then
			ptrField = fhCreateItem("ADDR",ptrEvent)
		end
		if fhGetValueAsText(ptrField) == "" then
			fhSetValueAsText(ptrField,"Registration District")
		end
	end

	-- For Death Add age if entered
	if intEvent == 3 and strPaged:len() > 0 then
		ptrField:MoveTo(ptrEvent,"~.AGE")
		if ptrField:IsNull() then
			ptrField = fhCreateItem("AGE",ptrEvent)
			fhSetValueAsText(ptrField,strPaged)
		end
	end

	-- Add Source Citation
	local strQtr = arrPeriod[intPquat + 1]
	local strAge = arrGROType[intEvent].." "..strQtr.." "..intPyear.." "..strPdist.." "..strPrefn
	if intEvent == 1 and strPmaid:len() > 1 then
		strAge = strAge.." Mothers Maiden Name: "..strPmaid
	end
	if intEvent == 3 and strPaged:len() > 0 then
		strAge = strAge.." Age: "..strPaged
	end
	local eDate = nil
	if intPdate > 0 then
		-- Record Entry Date
		eDate = fhNewDate()
		if intPdate == 1 then
			eDate:SetSimpleDate(fhCallBuiltInFunction("today"))
		else
			eDate:SetValueAsText(arrShortP[intPquat + 1].." "..intPyear)
		end
	end

	-- Add Citation to Event
	addSource(ptrEvent,ptrSource,strAge,intPcite,eDate,tblAssess[intPqual])

	-- Add Citation to Name(s)
	local tblTags = { {"~.NAME[1]"}; {"~.HUSB[1]>NAME[1]"; "~.WIFE[1]>NAME[1]"; "~.HUSB[2]>NAME[1]"; "~.WIFE[2]>NAME[1]"}; {"~.NAME[1]"}; }
	if intPname > 0 then
		for _, strTag in ipairs ( tblTags[intEvent] ) do
			ptrField:MoveTo(ptrList[1],strTag)
			if ptrField:IsNotNull() then
				addSource(ptrField,ptrSource,strAge,intPcite,eDate,tblAssess[intPqual])
			end
		end
	end

	-- Check Data
	ptrField:MoveTo(ptrEvent,"~.DATE")
	local strResult = fhCallBuiltInFunction("GetDataWarning",ptrField,1)
	if strResult ~= "" then
		local strButton = fhMessageBox(strResult.."\nDo you wish to undo the entry?","MB_YESNO","MB_ICONEXCLAMATION")
		if strButton == "Yes" then
			doError("Date Validation Failed")
		end
	end

end -- function main()

function addSource(ptrFact,ptrSource,strAge,intCite,eDate,strAssess)
	if intCite == 2 then -- Event Note Only
		local ptrNote = fhNewItemPtr()
		ptrNote:MoveTo(ptrFact,"~.NOTE2")
		if ptrNote:IsNull() then
			ptrNote = fhCreateItem("NOTE2",ptrFact)		-- FACT.NOTE2
		end
		local strNote = fhGetValueAsText(ptrNote)
		if strNote ~= "" then strNote = strNote.."\n" end
		strNote = strNote.."GRO Index "..strAge
		fhSetValueAsText(ptrNote,strNote)
	else -- intCite ~= 2 -- Add Citation
		local ptrCite = fhCreateItem("SOUR",ptrFact)		-- FACT.SOUR
		fhSetValueAsLink(ptrCite,ptrSource)
		local ptrData = fhNewItemPtr()
		local ptrAge  = fhNewItemPtr()
		if eDate or intCite == 1 then
			ptrData = fhCreateItem("DATA",ptrCite)			-- FACT.SOUR.DATA
		end
		if eDate then
			local ptrDate = fhCreateItem("DATE",ptrData)	-- FACT.SOUR.DATA.DATE
			fhSetValueAsDate(ptrDate,eDate)
		end
		if strAssess then
			ptrQuay = fhCreateItem("QUAY",ptrCite)			-- FACT.SOUR.QUAY
			fhSetValueAsText(ptrQuay,strAssess)
		end
		if intCite == 0 then
			ptrAge = fhCreateItem("PAGE",ptrCite)			-- FACT.SOUR.PAGE
		else
			ptrAge = fhCreateItem("TEXT",ptrData)			-- FACT.SOUR.DATA.TEXT
		end
		fhSetValueAsText(ptrAge,strAge)
	end
end -- function addSource

function getSpouseFamilies(ptrIndi)
	local arrFams = {}
	local ptrFams = fhNewItemPtr()
	ptrFams:MoveTo(ptrIndi,"~.FAMS")
	while ptrFams:IsNotNull() do
		table.insert(arrFams,fhGetValueAsLink(ptrFams))
		ptrFams:MoveNext("SAME_TAG")
	end
	return arrFams
end -- function getSpouseFamilies

function promptPlace(strDistrict)
	local arrPlaces = placeList(strDistrict)		-- List of Place names matching Registration District entered
	local arrPrompt = {}
	addParam( arrPrompt, "Please select a Place from the list or "	, "%t" )
	addParam( arrPrompt, "use the entry box to enter a Place name "	, "%t" )
	addParam( arrPrompt, "  Enter the District Place name: "			, "%s" )
	addParam( arrPrompt, "  Select from District Place list: "		, "%l|Use Place Above|"..table.concat(arrPlaces,"|").."|" )
	local strPrompt = table.concat(arrPrompt,"\n").."\n"
	local isOK, strPlace, intPlace = iup.GetParam("Select District Place Name", param_action, strPrompt, strDistrict, 0)
	-- Check for Cancel
	if not isOK then
		return strDistrict
	end
	if intPlace > 0 then
		strPlace = arrPlaces[intPlace]
	end
	return strPlace
end -- function promptPlace

function placeList(strFind)
	strFind = strFind:lower()
	local arrPlac = {}
	local ptrPlac = fhNewItemPtr()
	ptrPlac:MoveToFirstRecord("_PLAC")
	while ptrPlac:IsNotNull() do
		local strPlac = fhGetDisplayText(ptrPlac)
		if strPlac:lower():find(strFind) then
			table.insert(arrPlac,strPlac)
		end
		ptrPlac:MoveNext()
	end
	table.sort(arrPlac)
	return arrPlac
end -- function placeList

fhInitialise(7,0,0,"save_recommended")

main()

Source:Add-GRO-Index-Source-Citation.fh_lua