Record Baptism Data England and Wales.fh_lua

--[[
@Title: Record Baptism Data (England and Wales)
@Type: Source-driven Data Entry
@Subtype: "Church Register"
@Author: Helen Wright
@Version: 1.6
Changes added to modify TfS depending on what data is entered
Also allows unidentified father and/or mother
Fixed issue with &
Better UTF8 handling
Other minor fixes
@Keywords: 
@LastUpdated: November 2021
@GH  #24 #37 #54 #76 #110 #112 #119
@Description: Based on the format of the England and Wales Parish register before and after 1813, it allows details of baptism facts to be recorded, as well as details of parents and celebrants, creating records as necessary.  Only entry of information about the principal is mandatory.
]]

fhInitialise(7)
fh = require 'fhUtils'
fh.setIupDefaults()

-- Local Globals
local form, templateName, templateDefault
local iForm = 1
local sPluginName = fhGetContextInfo 'CI_PLUGIN_NAME'
local s = {} -- Autofill table
local pCite -- Citation Object
local tUpdatedFields = {} -- Added and updated fields
local cells = {} -- Main Dialog sections

--- Builds dialog and drives process.
function main()
	
	-- ------------------------------------------------------------Load citation and associated fields
	pCite = fh.loadPreparedCitation()

	if not pCite.result then
		fh.getParam(sPluginName, pCite.err)
		return
	end
	-- Ensure all needed fields have been completed
	if
		not (
			pCite:checkRequired(
				'EN-EVENT_TYPE',
				'NM-PRINCIPAL',
				'DT-DATE',
				'PL-LOCATION',
				'TX-CHURCH'
			)
		)
	then
		fh.getParam(
			sPluginName,
			'Not all required fields are set,\nplease ensure you have entered type, date, church, location and principal. '
		)
		return
	end
	if pCite:getValue 'EN-EVENT_TYPE' ~= 'Baptism' then
		fh.getParam(sPluginName, 'Only Baptism is supported by this plugin. ')
		return
	end

	-- Get form and load values from Citation
	dtEventDateString = pCite:getDisplayValue 'DT-DATE'
	dtEventDate = pCite:getValue 'DT-DATE'
	dtP1 = dtEventDate:GetDatePt1()
	dtYear = dtP1:GetYear()
	sDay = dtEventDate:GetDisplayText 'DAY'
	sMonth = dtEventDate:GetDisplayText 'MONTH_NAME'
	if dtYear < 1813 then
		iForm = 2
	end
	local masterForms = loadMasterForms()
	form = tablex.deepcopy(masterForms[iForm]['sections'])
	templateName = masterForms[iForm]['templateName']
	templateDefault = masterForms[iForm]['templateDefault']

	form.principal.fields[1].value = pCite:getValue 'NM-PRINCIPAL'

	-- ------------------------------------------------------------ Get currently selected person
	local ptrPrincipal = fh.getCurrentIndividual()
	if ptrPrincipal:IsNotNull() then
		form.principal.fields[field(form.principal.fields, 'RECORD')].value =
			ptrPrincipal:Clone()
		changePrincipal(ptrPrincipal, true)
	end
	-- ------------------------------------------------------------ Create Dialog
	for k, v in pairs(form) do
		grid = iup.gridbox {
			numdiv = 2,
			cgaplin = '1',
			cgapcol = '1',
			margin = '4x4',
			expand = 'YES',
			NORMALIZESIZE = 'HORIZONTAL',
		}
		for l, f in ipairs(v.fields) do
			if f.label then
				local label = '      '
				local value = '                                       '
				if f.gridDisplay or v.gridDisplay then
					label = f.label .. ':'
					value = getParamValueForDisplay(f, true)
					if value == f.label then
						value = utils.choose(f.value == true, 'Yes', 'No')
					end
					value = getParamValueForDisplay(f, true)
				end
				f.gridLabel = iup.label { title = label, size = '80', expand = 'NO' }
				iup.Append(grid, f.gridLabel)
				f.iupgrid = iup.label { title = value, expand = 'YES' }
				iup.Append(grid, f.iupgrid)
			end
		end
		v.button = iup.button { title = 'Edit', active = 'NO' }
		if v.active then
			v.button.active = 'YES'
		end
		v.button.action = function()
			doEdit(k, v.title, v.seq)
		end
		cells[v.seq] = iup.vbox {
			EXPANDCHILDREN = 'YES',
			EXPAND = 'YES',
			iup.frame {
				title = v.title,
				EXPANDCHILDREN = 'YES',
				EXPAND = 'YES',
				iup.vbox {
					EXPANDCHILDREN = 'YES',
					EXPAND = 'YES',
					v.button,
					grid,
				},
			},
		}
	end

	local placeList = fh.createPlaceList()
	s['PLAC'] = placeList
	s['OCCU'] = fhGetDataList 'OCCUPATIONS'
	local addressList = {}

	txtMessage = iup.label {
		title = ' Hint: please edit the Principal section to enable the other sections',
	}

	btnOk = iup.button { title = 'OK', padding = '20x4', expand = 'HORIZONTAL' }

	function btnOk.action()
		if form.principal.valid then
			local sVenue = pCite:getValue 'TX-CHURCH'
			if not sVenue then
				sVenue = pCite:getValue 'AD-ADDRESS'
			end
			processBaptism(pCite:getValue 'PL-LOCATION', sVenue)
			return iup.CLOSE
		else
			fhMessageBox 'Information has not been entered on Principal'
		end
	end
	btnCancel = iup.button {
		title = 'Cancel',
		padding = '4x4',
		expand = 'HORIZONTAL',
	}

	function btnCancel.action()
		return iup.CLOSE
	end

	local sTitle = 'Baptism Entry: ' .. fhGetDisplayText(pCite.source)
	dlg = iup.dialog {
		title = sTitle,
		minsize = '1000',
		iup.vbox {
			EXPANDCHILDREN = 'YES',
			EXPAND = 'YES',

			iup.gridbox {
				numdiv = 2,
				cgaplin = '1',
				cgapcol = '1',
				margin = '4x4',
				expand = 'YES',
				EXPANDCHILDREN = 'YES',
				table.unpack(cells),
			},
			iup.hbox {
				margin = '4x4',
				expand = 'NO',
				btnOk,
				btnCancel,
				fh.helpButton 'record-baptism-data-uk',
				txtMessage,
			},
		},
	}
	iup.SetAttribute(dlg, 'NATIVEPARENT', fhGetContextInfo 'CI_PARENT_HWND') -- Set the parent window handle
	iup.SetHandle('main', dlg)
	iup.SetGlobal('PARENTDIALOG', 'main')

	iup.Popup(dlg)
	iup.Destroy(dlg)
end
-- --------------------------------------------------------------- doEdit
--- Called from the Edit buttons to update the sections
-- @param sType string, section name from form table
-- @param sTitle string Name of dialog
-- @param seq  number, sequence number of section
function doEdit(sType, sTitle, seq)
	local fields = form[sType].fields
	if sType == 'principal' then
		local oldRecord =
			form[sType]['fields'][field(fields, 'RECORD')].value:Clone()
		local oldFamily = form[sType]['fields'][field(fields, 'FAMILY')]

		if oldFamily.value then
			oldFamily = oldFamily.value:Clone()
		else
			oldFamily = fhNewItemPtr()
		end
		local r = fh.getParam(
			'Enter ' .. sTitle,
			nil,
			fields,
			{ 'OK', 'Cancel', fh.helpButton 'record-baptism-data-uk-principal' },
			s
		)
		if r.ok then
			form[sType].valid = true
			-- enable all Edit buttons
			for k, v in pairs(form) do
				v.button.active = 'YES'
			end
			-- To Do Ripple all fields

			if
				not (oldRecord:IsSame(r.results['RECORD']))
				or not (oldFamily:IsSame(r.results['FAMILY']))
			then
				changePrincipal(r.results['RECORD'])
			end
		end
	else
		local r = fh.getParam(
			'Enter ' .. sTitle,
			nil,
			fields,
			{ 'OK', 'Cancel' },
			s
		)
		if r.ok then
			form[sType].valid = true
			form[sType].gridDisplay = true
		end
	end
	updateGrid()
end
-- --------------------------------------------------------------- changePrincipal
--- Update other section/grid boxes when the Principal record is changed
-- @param ptrPrincipal fhItemPointer for the Principal person on the certifcate
-- @param init  boolean, true on first run.

function changePrincipal(ptrPrincipal, init)
	local f = form['principal'].fields
	if ptrPrincipal:IsNotNull() then
		if init then
			-- first time load or new Record selected

			local values, prompts = updateFamList(ptrPrincipal, 'FamilyAsChild')
			f[field(f, 'FAMILY')].values = values
			f[field(f, 'FAMILY')].prompts = prompts
			f[field(f, 'FAMILY')].value = values[1]

			f[field(f, 'ACTION')].value = 'select'
			f[field(f, 'FAMILY')].protect = false
			f[field(f, 'RECORD')].protect = false
		end

		f[field(f, 'SEX')].value = fhGetItemText(ptrPrincipal, '~.SEX')
		-- f[field(f,'SEX')].protect = true

		local ptrFam = f[field(f, 'FAMILY')].value
		if ptrFam:IsNotNull() then
			-- Set up Father of Principal if they exist
			local ptrF = fhGetItemPtr(ptrFam, '~.HUSB>')
			if ptrF:IsNotNull() then
				local s = form['father'].fields
				s[field(s, 'NAME')].value = fh.editableName(
					fhGetItemText(ptrF, '~.NAME:STORED')
				)
				s[field(s, 'RECORD')].value = ptrF:Clone()
				s[field(s, 'RECORD')].protect = true
				s[field(s, 'ACTION')].value = 'select'
				s[field(s, 'ACTION')].protect = true
			end
			-- Set up Mother of Principal if they exist
			local ptrF = fhGetItemPtr(ptrFam, '~.WIFE>')
			if ptrF:IsNotNull() then
				local s = form['mother'].fields
				s[field(s, 'NAME')].value = fh.editableName(
					fhGetItemText(ptrF, '~.NAME:STORED')
				)
				s[field(s, 'RECORD')].value = ptrF:Clone()
				s[field(s, 'RECORD')].protect = true
				s[field(s, 'ACTION')].value = 'select'
				s[field(s, 'ACTION')].protect = true
			end
		else
			resetSection 'father'
			resetSection 'mother'
		end
	else
		resetSection 'father'
		resetSection 'mother'
	end
end

-- --------------------------------------------------------------- resetSection
--- Reset the section values from the master form
-- @param formSection string section index
function resetSection(formSection)
	for k, v in ipairs(masterForms[iForm].sections[formSection].fields) do
		for m, u in pairs(v) do
			form[formSection]['fields'][k][m] = u
		end
	end
	updateGrid()
end

-- --------------------------------------------------------------- updateGrid
--- Update All Grid Fields from table
function updateGrid()
	for sType, sSection in pairs(form) do
		for l, f in ipairs(sSection.fields) do
			local label = ' '
			local value = ' '
			if f.gridDisplay or form[sType].gridDisplay then
				label = f.label
				value = fh.getParamValueForDisplay(f, true)
				if value == f.label then
					value = utils.choose(f.value == true, 'Yes', 'No')
				end
			end
			if f.gridLabel then
				f.gridLabel.title = label
			end
			if f.iupgrid then
				f.iupgrid.title = value
			end
		end
	end
end

function processBaptism(sPlace, sAddress, sCelebrant)
	local fields = {}
	local data = {}
	for k, s in pairs(form) do
		data[k] = {}
		for i, f in ipairs(s.fields) do
			data[k][f.tag] = { value = f.value, type = f.type, dr = f.df }
		end
	end

	-- Create needed Individual Records
	for _, f in pairs(data) do
		if f.ACTION and f.ACTION.value == 'create' then
			local sex
			if f.SEX and f.SEX.value then
				sex = f.SEX.value
			end
			local ptr = fh.createIndi(f.NAME.value, sex)
			addCitation(ptr, 'Created')
			local ptrName = fhGetItemPtr(ptr, '~.NAME')
			addCitation(ptrName, 'Cited')
			f.RECORD.value:MoveTo(ptr)
		end
	end

	processParents(
		data.father.RECORD.value,
		data.mother.RECORD.value,
		data.principal.RECORD.value
	)
	local eventDate = pCite:getValue 'DT-DATE'
	local sPlace = pCite:getValue 'PL-LOCATION'
	local sChurch = pCite:getValue 'TX-CHURCH'
	-- Create / Update Baptism Event
	local ptrBaptism = fhGetItemPtr(data.principal.RECORD.value, '~.BAPM')
	local sAction = ''
	--Create/Update baptism event
	if ptrBaptism:IsNotNull() then
		ptrBaptism, sAction = fh.createUpdateFact(
			data.principal.RECORD.value,
			'BAPM',
			'Baptism',
			sPlace,
			eventDate,
			sChurch
		)
		if ptrBaptism then
			addCitation(ptrBaptism, sAction)
		end
	else
		ptrBaptism = fh.createFact(
			data.principal.RECORD.value,
			'BAPM',
			sPlace,
			eventDate,
			sChurch
		)
		if ptrBaptism then
			addCitation(ptrBaptism, 'Added')
		end
	end

	--Create/Update Birth fact is Age or Date of Birth specified
	if dtYear > 1812 then
		local dtBirth = fhNewDate()
		if fh.isSet(data.principal.DATE.value) then
			dtBirth = data.principal.DATE.value
		else
			if fh.isSet(data.principal.AGE.value) then
				dtBirth = fh.calcBirth(eventDate, data.principal.AGE.value)
			end
		end
		if not (dtBirth:IsNull()) then
			local ptrBirth = fhGetItemPtr(data.principal.RECORD.value, '~.BIRT')
			ptrBirth, sAction = fh.createUpdateFact(
				data.principal.RECORD.value,
				'BIRT',
				'Birth',
				nil,
				dtBirth
			)
			if ptrBirth then
				addCitation(ptrBirth, sAction)
			end
		end
	end

	for k, f in pairs(data) do
		if ptrBaptism and k == 'celebrant' then -- Add celebrant as witness if not name only
			if f.ACTION.value == 'name' and fh.isSet(f.NAME.value) then
				fh.addWitness(ptrBaptism, f.NAME.value, f.ROLE.value)
			elseif fh.isSet(f.RECORD.value) then
				fh.addWitness(ptrBaptism, f.RECORD.value, f.ROLE.value)
			end
		end
		if f.RECORD and fh.isSet(f.RECORD.value) then -- Add occupation if specified
			if f.OCCU and f.OCCU.value:len() > 0 then
				local ptrFact
				ptrFact, sAction = fh.createFact(
					f.RECORD.value,
					'OCCU',
					nil,
					eventDate,
					nil,
					f.OCCU.value
				)
				if ptrFact then
					addCitation(ptrFact, 'Added')
				end
			end
		end
		if f.PLAC and f.PLAC.value:len() > 0 then -- add residence if specified
			local ptrFact, sAction = fh.createFact(
				f.RECORD.value,
				'RESI',
				f.PLAC.value,
				eventDate,
				f.ADDR.value
			)
			if ptrFact then
				addCitation(ptrFact, 'Added')
			end
			for _, r in pairs { data.father.RECORD.value, data.mother.RECORD.value } do
				if fh.isSet(r) then
					local ptrFact, sAction = fh.createFact(
						r,
						'RESI',
						f.PLAC.value,
						eventDate,
						f.ADDR.value
					)
					if ptrFact then
						addCitation(ptrFact, 'Added')
					end
				end
			end
		end
	end
	-- Create text from source template
	local fields = {}
	for k, s in pairs(form) do
		for i, f in ipairs(s.fields) do
			local inx = string.upper(k .. '.' .. tostring(f.tag))
			fields[inx] = fh.getParamValueForDisplay(f)
			if f.tag == 'NAME' and k == 'principal' then
				fields['PRINCIPAL.NAMEUNLINKED'] = fields[inx]
			end
			if f.tag == 'NAME' and data[k].RECORD then
				local ptr = data[k].RECORD.value
				if ptr:IsNotNull() then
					-- Add record link
					fields[inx] = fh.richTextRecordLink(ptr, fields[inx])
				end
			end
		end
	end

	if stringx.strip(fields['PRINCIPAL.NOTES']) ~= '' then
		fields['PRINCIPAL.NOTES'] = 'Notes: '
			.. stringx.strip(fields['PRINCIPAL.NOTES'])
	end
	fields['BAPTISM.YEAR'] = tostring(dtYear)
	fields['BAPTISM.DAY'] = utils.choose(sDay == '0', '', sDay)
	fields['BAPTISM.MONTH'] = sMonth

	if dtYear < 1813 then
		local sFather = stringx.strip(fields['FATHER.NAME'])
		local sMother = stringx.strip(fields['MOTHER.NAME'])
		local sPlace = stringx.strip(fields['PRINCIPAL.PLAC'])
		local sAddr = stringx.strip(fields['PRINCIPAL.ADDR'])
		if sAddr ~= '' then
			fields['PRINCIPAL.ADDR'] = ' of ' .. sAddr
		elseif sPlace ~= '' then
			fields['PRINCIPAL.PLAC'] = ' of ' .. sPlace
		end
		if sFather ~= '' or sMother ~= '' then
			fields['PRINCIPAL.NAME'] = fields['PRINCIPAL.NAME']
				.. utils.choose(
					fields['PRINCIPAL.SEX'] == 'Male',
					' son of',
					' daughter of'
				)
		end
		fields['FATHER.NAME'] = sFather
			.. utils.choose(sFather == '' or sMother == '', '', ' and ')
	else
		if stringx.strip(fields['PRINCIPAL.AGE']) ~= '' then
			fields['PRINCIPAL.AGE'] = 'Age: '
				.. stringx.strip(fields['PRINCIPAL.AGE'])
				.. '\n'
		end
		if stringx.strip(fields['PRINCIPAL.DATE']) ~= '' then
			fields['PRINCIPAL.DATE'] = 'Born: '
				.. stringx.strip(fields['PRINCIPAL.DATE'])
				.. '\n'
		end
		if stringx.strip(fields['PRINCIPAL.NOTES']) ~= '' then
			fields['PRINCIPAL.NOTES'] = fields['PRINCIPAL.NOTES'] .. '\n'
		end
		if pCite:getDisplayValue 'TX-REFERENCE' then
			fields['REFERENCE'] = 'Reference: '
				.. pCite:getDisplayValue 'TX-REFERENCE'
		end
	end

	sText = fh.formatTextFromSource(templateName, templateDefault, pCite, fields)

	fh.createTextFromSource(pCite, sText, 'source')
	fh.outputUpdatedFields(tUpdatedFields, pCite)
end

function beforeDate(dt)
	local newDate = fhNewDate()
	if dt:IsNull() then
		return
	end
	dp = dt:GetDatePt1()
	if dp:IsNull() then
		return
	end
	newDate:SetRange('before', dp)
	return newDate
end

function addCitation(ptr, action)
	local action = action or ''
	table.insert(tUpdatedFields, { ptr:Clone(), action })
	pCite:appendCitation(ptr)
end
function processParents(ptrFather, ptrMother, ptrChild)
	local ptrFamC = fhNewItemPtr()
	local ptrFam = fhNewItemPtr()
	local ptrHusb = fhNewItemPtr()
	local ptrWife = fhNewItemPtr()
	local bFamc = false
	ptrFamC:MoveTo(ptrChild, '~.FAMC')
	while ptrFamC:IsNotNull() do
		ptrHusb:MoveTo(ptrFamC, '~>HUSB>')
		ptrWife:MoveTo(ptrFamC, '~>WIFE>')
		if
			ptrHusb:IsSame(ptrFather)
			and (ptrWife:IsSame(ptrMother) or ptrWife:IsNull())
		then
			ptrFam:MoveTo(ptrFamC, '~>')
			bFamc = true
		elseif
			ptrWife:IsSame(ptrMother)
			and (ptrHusb:IsSame(ptrFather) or ptrHusb:IsNull())
		then
			ptrFam:MoveTo(ptrFamC, '~>')
			bFamc = true
		end
		ptrFamC:MoveNext 'SAME_TAG'
	end
	-- Check if selected people already married
	if not bFamc then
		local ptrChk = fhGetItemPtr(ptrFather, '~.FAMS')
		local ptrWifeChk = fhNewItemPtr()
		while ptrChk:IsNotNull() do
			ptrWifeChk:MoveTo(ptrChk, '~>WIFE>')
			if ptrWifeChk:IsSame(ptrMother) then
				ptrFam:MoveTo(ptrChk, '~>')
			end
			ptrChk:MoveNext 'SAME_TAG'
		end
		if ptrFam:IsNotNull() then
			fh.addFamilyAsChild(ptrChild, ptrFam)
		end
	end
	if ptrFather:IsNotNull() or ptrMother:IsNotNull() then
		if ptrFam:IsNull() then
			ptrFam = fh.createFamilyAsChild(ptrChild)
			addCitation(ptrFam, 'Created')
		end
		if fhGetItemPtr(ptrFam, '~.HUSB>'):IsNull() and ptrFather:IsNotNull() then
			fh.addFamilyAsSpouse(ptrFather, ptrFam)
		end
		if fhGetItemPtr(ptrFam, '~.WIFE>'):IsNull() and ptrMother:IsNotNull() then
			fh.addFamilyAsSpouse(ptrMother, ptrFam)
		end
	end
end

function ptrDescription(ptr)
	local strDesc = ''
	local strTag = fhGetTag(ptr)
	if not (fhHasParentItem(ptr)) then
		strDesc = 'Record (' .. fhGetTag(ptr) .. ')'
	else
		local strTitle = string.match(fhGetDisplayText(ptr), '([%a%w%s]*):')
		if not strTitle then
			strTitle = string.match(fhGetDisplayText(ptr), '(%a*)')
		end
		strDesc = strTitle .. ' (' .. strTag .. ')'
	end
	return strDesc
end
--------------------------------------------------------------------------- getParamValueForDisplay
function getParamValueForDisplay(field)
	local s = ''
	local type = field.type or 'STRING'
	if field.value then
		if type == 'RECORD' then
			if fh.isSet(field.value) then
				s = fhGetDisplayText(field.value)
			elseif fh.isSet(field.value.ptr) then
				s = fhGetDisplayText(field.value.ptr)
			else
				s = 'N/A'
			end
		elseif type == 'DATE' then
			if fh.isSet(field.value) then
				s = field.value:GetAsText()
			end
		elseif type == 'LIST' then
			for l, k in pairs(field.values) do
				if k == field.value then
					if field.prompts then
						s = field.prompts[l]
					else
						s = field.values[l]
					end
				end
			end
		elseif type == 'BOOLEAN' then
			if field.value then
				s = field.label
			else
				s = ''
			end
		else
			s = tostring(field.value)
		end
	end
	return s
end

function selectOrCreate(value)
	if value == 'select' then
		return false, 1
	else
		return true, 0
	end
end

function selectOrCreatePrincipal()
	if value == 'select' then
		return false, 1
	else
		-- data.principal.SEX.protect = false
		return true, 0
	end
end

function updateFamList(ptr)
	local ptrs = { fhNewItemPtr() }
	local prompts = { 'New Family As Child' }
	if fh.isSet(ptr) then
		local famList = fh.familyList(ptr, 'FamilyAsChild')
		for i, tFam in ipairs(famList) do
			table.insert(ptrs, tFam.ptr)
			table.insert(prompts, tFam.label)
		end
	end
	return ptrs, prompts
end

function field(fields, tag)
	local i
	for i, v in ipairs(fields) do
		if tag == v.tag then
			return i
		end
	end
end

function updateAddressList(...)
	args = { ... }
	print ',,,'
end

function loadMasterForms()
	ptrFamily = fhNewItemPtr()
	masterForms = {}
	masterForms[1] = {
		templateName = 'Baptism post 1812 (England and Wales).ftf',
		templateDefault = [[Baptism {PRINCIPAL.NAMEUNLINKED} {DT-DATE} {TX-CHURCH} {PL-LOCATION}

Baptisms solemnised in the Parish of {TX-CHURCH} {PL-LOCATION} in the Year {BAPTISM.YEAR}


 When Baptised | Child's Christian Name | Parents' Names | Abode | Quality Trade or Profession | By Whom the ceremony was performed 
 {BAPTISM.DAY} {BAPTISM.MONTH} | {PRINCIPAL.NAME} | {FATHER.NAME} 
{MOTHER.NAME} | {PRINCIPAL.ADDR}
{PRINCIPAL.PLAC} | {FATHER.OCCU} | {CELEBRANT.NAME}
 


{PRINCIPAL.AGE}{PRINCIPAL.DATE}{PRINCIPAL.NOTES}{REFERENCE}
]],
		sections = {
			principal = {
				fields = {
					{
						tag = 'NAME',
						label = 'Name',
						type = 'STRING',
						dr = 'NAME',
						value = pCite:getValue 'NM-PRINCIPAL',
						minlength = 1,
						protect = true,
					},
					{
						tag = 'ACTION',
						label = 'Add principal as',
						type = 'LIST',
						value = 'create',
						values = { 'create', 'select' },
						prompts = { 'Create New Record', 'Use Existing Record' },
						child = 'RECORD',
						childUpdate = function(...)
							return selectOrCreate(...)
						end,
					},
					{
						tag = 'RECORD',
						label = 'Record',
						type = 'RECORD',
						dr = 'PTR',
						value = fhNewItemPtr(),
						protect = true,
						child = 'FAMILY',
						childUpdate = function(...)
							return updateFamList(...)
						end,
					},
					{
						tag = 'FAMILY',
						label = 'Family',
						type = 'LIST',
						value = ptrFamily,
						values = { ptrFamily },
						prompts = { 'New Family as Child' },
					},
					{
						tag = 'SEX',
						type = 'LIST',
						label = 'Sex',
						dr = 'SEX',
						value = 'Male',
						values = { 'Male', 'Female', 'Unknown' },
					},
					{
						tag = 'AGE',
						type = 'STRING',
						label = 'Age',
						value = '',
						mask = '(/d+[dwmyf]|full)',
						minlength = 0,
					},
					{
						tag = 'DATE',
						type = 'DATE',
						label = 'Birth Date',
						value = fhNewDate(),
					},
					{
						tag = 'PLAC',
						type = 'STRING',
						label = 'Abode Place',
						dr = 'RESI.PLAC',
						value = '',
						child = 'ADDR',
						childUpdate = function(place)
							return fh.createAddressList(place)
						end,
					},
					{
						tag = 'ADDR',
						type = 'STRING',
						label = 'Abode Address',
						dr = 'RESI.ADDR',
						value = '',
					},
					{ tag = 'NOTES', label = 'Notes', type = 'STRING', value = '' },
					{ tag = 'BAPM', dr = 'BAPM' },
				},
				title = 'Principal',
				label = 'principal',
				seq = 1,
				active = true,
				gridDisplay = true,
			},
			father = {
				fields = {
					{
						tag = 'NAME',
						label = 'Name',
						type = 'STRING',
						dr = 'NAME',
						value = '',
						minlength = 0,
						gridDisplay = true,
					},
					{
						tag = 'ACTION',
						label = 'Add father as',
						type = 'LIST',
						value = 'name',
						values = { 'name', 'create', 'select' },
						prompts = {
							'Name Only',
							'Create New Record',
							'Use Existing Record',
						},
						child = 'RECORD',
						childUpdate = selectOrCreate,
					},
					{
						tag = 'RECORD',
						label = 'Record',
						type = 'RECORD',
						recordtype = 'INDI',
						value = fhNewItemPtr(),
						protect = true,
					},
					{
						tag = 'OCCU',
						dr = 'OCCU',
						type = 'STRING',
						label = 'Occupation',
						value = '',
					},
					{ tag = 'SEX', value = 'Male' },
				},
				title = 'Father',
				seq = 3,
				gridDisplay = true,
			},
			mother = {
				fields = {
					{
						tag = 'NAME',
						label = 'Name',
						type = 'STRING',
						dr = 'NAME',
						value = '',
						minlength = 0,
						gridDisplay = true,
					},
					{
						tag = 'ACTION',
						label = 'Add mother as',
						type = 'LIST',
						value = 'name',
						values = { 'name', 'create', 'select' },
						prompts = {
							'Name Only',
							'Create New Record',
							'Use Existing Record',
						},
						child = 'RECORD',
						childUpdate = selectOrCreate,
					},
					{
						tag = 'RECORD',
						label = 'Record',
						type = 'RECORD',
						recordtype = 'INDI',
						value = fhNewItemPtr(),
						protect = true,
					},
					{ tag = 'SEX', value = 'Female' },
				},
				title = 'Mother',
				seq = 4,
				gridDisplay = true,
			},
			celebrant = {
				fields = {
					{
						tag = 'NAME',
						label = 'Name',
						type = 'STRING',
						dr = 'NAME',
						value = '',
						minlength = 1,
					},
					{
						tag = 'ACTION',
						label = 'Add celebrant as',
						type = 'LIST',
						value = 'name',
						values = { 'name', 'create', 'select' },
						prompts = {
							'Name Only',
							'Create New Record',
							'Use  Existing Record',
						},
						child = 'RECORD',
						childUpdate = selectOrCreate,
					},
					{
						tag = 'RECORD',
						label = 'Record',
						type = 'RECORD',
						recordtype = 'INDI',
						value = fhNewItemPtr(),
						protect = true,
					},
					{
						tag = 'ROLE',
						label = 'Role',
						type = 'LIST',
						value = 'None',
						values = { 'None', 'Minister', 'Priest' },
					},
				},
				title = 'Celebrant',
				seq = 2,
				gridDisplay = true,
			},
		},
	}

	--set up pre 1813 variant

	masterForms[2] = tablex.deepcopy(masterForms[1])
	masterForms[2].templateName = 'Baptism pre 1813 (England and Wales).ftf'
	masterForms[2].templateDefault =
		[[Baptism {PRINCIPAL.NAMEUNLINKED} {DT-DATE} {TX-CHURCH} {PL-LOCATION}

Baptisms solemnised in the Parish of {TX-CHURCH} {PL-LOCATION} in the Year {BAPTISM.YEAR}

{BAPTISM.DAY} {BAPTISM.MONTH} {PRINCIPAL.NAME} {FATHER.NAME}{MOTHER.NAME}{PRINCIPAL.ADDR} {PRINCIPAL.PLAC}

{PRINCIPAL.NOTES}
]]
	masterForms[2].sections = {
		principal = {
			fields = {
				{
					tag = 'NAME',
					label = 'Name',
					type = 'STRING',
					dr = 'NAME',
					value = pCite:getValue 'NM-PRINCIPAL',
					minlength = 1,
					protect = true,
				},
				{
					tag = 'ACTION',
					label = 'Add principal as',
					type = 'LIST',
					value = 'create',
					values = { 'create', 'select' },
					prompts = { 'Create New Record', 'Use Existing Record' },
					child = 'RECORD',
					childUpdate = function(...)
						return selectOrCreate(...)
					end,
				},
				{
					tag = 'RECORD',
					label = 'Record',
					type = 'RECORD',
					dr = 'PTR',
					value = fhNewItemPtr(),
					protect = true,
					child = 'FAMILY',
					childUpdate = function(...)
						return updateFamList(...)
					end,
				},
				{
					tag = 'FAMILY',
					label = 'Family',
					type = 'LIST',
					value = ptrFamily,
					values = { ptrFamily },
					prompts = { 'New Family as Child' },
				},
				{
					tag = 'SEX',
					type = 'LIST',
					label = 'Sex',
					dr = 'SEX',
					value = 'Male',
					values = { 'Male', 'Female', 'Unknown' },
				},
				{
					tag = 'PLAC',
					type = 'STRING',
					label = 'Abode Place',
					dr = 'RESI.PLAC',
					value = '',
					child = 'ADDR',
					childUpdate = function(place)
						return fh.createAddressList(place)
					end,
				},
				{
					tag = 'ADDR',
					type = 'STRING',
					label = 'Abode Address',
					dr = 'RESI.ADDR',
					value = '',
				},
				{ tag = 'NOTES', label = 'Notes', type = 'STRING', value = '' },
				{ tag = 'BAPM', dr = 'BAPM' },
			},
			title = 'Principal',
			label = 'Principal',
			seq = 1,
			active = true,
			gridDisplay = true,
		},
		father = {
			fields = {
				{
					tag = 'NAME',
					label = 'Name',
					type = 'STRING',
					dr = 'NAME',
					value = '',
					minlength = 0,
					gridDisplay = true,
				},
				{
					tag = 'ACTION',
					label = 'Add father as',
					type = 'LIST',
					value = 'name',
					values = { 'name', 'create', 'select' },
					prompts = {
						'Name Only',
						'Create New Record',
						'Use Existing Record',
					},
					child = 'RECORD',
					childUpdate = selectOrCreate,
				},
				{
					tag = 'RECORD',
					label = 'Record',
					type = 'RECORD',
					recordtype = 'INDI',
					value = fhNewItemPtr(),
					protect = true,
				},
				{ tag = 'SEX', value = 'Male' },
			},
			title = 'Father',
			seq = 2,
		},
		mother = {
			fields = {
				{
					tag = 'NAME',
					label = 'Name',
					type = 'STRING',
					dr = 'NAME',
					value = '',
					minlength = 0,
					gridDisplay = true,
				},
				{
					tag = 'ACTION',
					label = 'Add mother as',
					type = 'LIST',
					value = 'name',
					values = { 'name', 'create', 'select' },
					prompts = {
						'Name Only',
						'Create New Record',
						'Use Existing Record',
					},
					child = 'RECORD',
					childUpdate = selectOrCreate,
				},
				{
					tag = 'RECORD',
					label = 'Record',
					type = 'RECORD',
					recordtype = 'INDI',
					value = fhNewItemPtr(),
					protect = true,
				},
				{ tag = 'SEX', value = 'Female' },
			},
			title = 'Mother',
			seq = 3,
		},
	}
	return masterForms
end
-------------------------------------------------------------------------------------------------------- Start Plugin
main()

Source:Record-Baptism-Data-England-and-Wales-5.fh_lua