Possible Problem Report.fh_lua

--[[
@Title: Possible Problem Manager
@Author: Jane Taubman
@LastUpdated: July 2011
@Version: 1.0
@Description: Lists all Possible Date Problems, similar the standard Fact Date Warning Query,  
but ignores those facts marked using Possible Problem Marker Plugin.
]]
require "iuplua"
-- require "_tableloadsave"
--[[
   Save Table to File/Stringtable
   Load Table from File/Stringtable
   v 0.94
   
   Lua 5.1 compatible
   
   Userdata and indices of these are not saved
   Functions are saved via string.dump, so make sure it has no upvalues
   References are saved
   ----------------------------------------------------
   table.save( table [, filename] )
   
   Saves a table so it can be called via the table.load function again
   table must a object of type 'table'
   filename is optional, and may be a string representing a filename or true/1
   
   table.save( table )
      on success: returns a string representing the table (stringtable)
      (uses a string as buffer, ideal for smaller tables)
   table.save( table, true or 1 )
      on success: returns a string representing the table (stringtable)
      (uses io.tmpfile() as buffer, ideal for bigger tables)
   table.save( table, "filename" )
      on success: returns 1
      (saves the table to file "filename")
   on failure: returns as second argument an error msg
   ----------------------------------------------------
   table.load( filename or stringtable )
   
   Loads a table that has been saved via the table.save function
   
   on success: returns a previously saved table
   on failure: returns as second argument an error msg
   ----------------------------------------------------
   
   chillcode, http://lua-users.org/wiki/SaveTableToFile
   Licensed under the same terms as Lua itself.
]]--
do
   -- declare local variables
   --// exportstring( string )
   --// returns a "Lua" portable version of the string
   local function exportstring( s )
      s = string.format( "%q",s )
      -- to replace
      s = string.gsub( s,"\\\n","\\n" )
      s = string.gsub( s,"\r","\\r" )
      s = string.gsub( s,string.char(26),"\"..string.char(26)..\"" )
      return s
   end
--// The Save Function
function table.save(  tbl,filename )
   local charS,charE = "   ","\n"
   local file,err
   -- create a pseudo file that writes to a string and return the string
   if not filename then
      file =  { write = function( self,newstr ) self.str = self.str..newstr end, str = "" }
      charS,charE = "",""
   -- write table to tmpfile
   elseif filename == true or filename == 1 then
      charS,charE,file = "","",io.tmpfile()
   -- write table to file
   -- use io.open here rather than io.output, since in windows when clicking on a file opened with io.output will create an error
   else
      file,err = io.open( filename, "w" )
      if err then return _,err end
   end
   -- initiate variables for save procedure
   local tables,lookup = { tbl },{ [tbl] = 1 }
   file:write( "return {"..charE )
   for idx,t in ipairs( tables ) do
      if filename and filename ~= true and filename ~= 1 then
         file:write( "-- Table: {"..idx.."}"..charE )
      end
      file:write( "{"..charE )
      local thandled = {}
      for i,v in ipairs( t ) do
         thandled[i] = true
         -- escape functions and userdata
         if type( v ) ~= "userdata" then
            -- only handle value
            if type( v ) == "table" then
               if not lookup[v] then
                  table.insert( tables, v )
                  lookup[v] = #tables
               end
               file:write( charS.."{"..lookup[v].."},"..charE )
            elseif type( v ) == "function" then
               file:write( charS.."loadstring("..exportstring(string.dump( v )).."),"..charE )
            else
               local value =  ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
               file:write(  charS..value..","..charE )
            end
         end
      end
      for i,v in pairs( t ) do
         -- escape functions and userdata
         if (not thandled[i]) and type( v ) ~= "userdata" then
            -- handle index
            if type( i ) == "table" then
               if not lookup[i] then
                  table.insert( tables,i )
                  lookup[i] = #tables
               end
               file:write( charS.."[{"..lookup[i].."}]=" )
            else
               local index = ( type( i ) == "string" and "["..exportstring( i ).."]" ) or string.format( "[%d]",i )
               file:write( charS..index.."=" )
            end
            -- handle value
            if type( v ) == "table" then
               if not lookup[v] then
                  table.insert( tables,v )
                  lookup[v] = #tables
               end
               file:write( "{"..lookup[v].."},"..charE )
            elseif type( v ) == "function" then
               file:write( "loadstring("..exportstring(string.dump( v )).."),"..charE )
            else
               local value =  ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
               file:write( value..","..charE )
            end
         end
      end
      file:write( "},"..charE )
   end
   file:write( "}" )
   -- Return Values
   -- return stringtable from string
   if not filename then
      -- set marker for stringtable
      return file.str.."--|"
   -- return stringttable from file
   elseif filename == true or filename == 1 then
      file:seek ( "set" )
      -- no need to close file, it gets closed and removed automatically
      -- set marker for stringtable
      return file:read( "*a" ).."--|"
   -- close file and return 1
   else
      file:close()
      return 1
   end
end

--// The Load Function
function table.load( sfile )
   -- catch marker for stringtable
   if string.sub( sfile,-3,-1 ) == "--|" then
      tables,err = loadstring( sfile )
   else
      tables,err = loadfile( sfile )
   end
   if err then return _,err
   end
   tables = tables()
   for idx = 1,#tables do
      local tolinkv,tolinki = {},{}
      for i,v in pairs( tables[idx] ) do
         if type( v ) == "table" and tables[v[1]] then
            table.insert( tolinkv,{ i,tables[v[1]] } )
         end
         if type( i ) == "table" and tables[i[1]] then
            table.insert( tolinki,{ i,tables[i[1]] } )
         end
      end
      -- link values, first due to possible changes of indices
      for _,v in ipairs( tolinkv ) do
         tables[idx][v[1]] = v[2]
      end
      -- link indices
      for _,v in ipairs( tolinki ) do
         tables[idx][v[2]],tables[idx][v[1]] =  tables[idx][v[1]],nil
      end
   end
   return tables[1]
end
-- close do
end
function getFactId(ptr,ptrEvent)
            local tblRecord = {recordid=fhGetRecordId(ptr),
								    type=fhGetTag(ptr),
									date=fhGetItemText(ptrEvent,'~.DATE'),
                                plac=fhGetItemText(ptrEvent,'~.PLAC'),
                                tag=fhGetTag(ptrEvent),
                                value=fhGetItemText(ptrEvent,'~')}

    return buildIndex(tblRecord)
end

function buildIndex(record)
    return (record.type..'|'..record.recordid..'|'..record.tag..'|'..record.date..'|'..record.plac..'|'..record.value)
end
function checkMark(record)
    local mark = 0
    if Settings[buildIndex(record)] ~= nil then
        mark = 1
    end
    return mark
end
--------------------------------------------------------------Main Code
-- Create Result Tables
tblIndi = {}
tblSpouse  = {}
tblFact = {}
tblFather = {}
tblMother = {}
tblReason = {}
tblMarks  = {}
-- Load Settings
strSettings = fhGetPluginDataFileName()
-- Fix File name
strSettings =strSettings:gsub('Data\\.-\.dat','Data\\Possible Problem Manager.dat')
Settings = table.load(strSettings)
if Settings == nil then Settings = {} end  -- First Run set empty Settings File	
-- Prompt User 
	strReportTitle = "Fact Problem Report"

btnNo = iup.Alarm(strReportTitle, "Include Facts marked 'Ignore' on the Report?" ,
                   "All Problem Facts" ,"Un-Ignored Facts Only" ,"Ignored Facts Only")
 
-- Shows a message for each selected button
if btnNo == 1 then
	bIncludeMarks = true
	bExcludeUnMarked = false
	strReportSubTitle = "All Problem Facts"
elseif btnNo == 2 then
	bIncludeMarks = false
	bExcludeUnMarked = false
	strReportSubTitle = "Un-Ignored Facts Only"
elseif btnNo == 3 then
	bIncludeMarks = true
	bExcludeUnMarked = true
	strReportSubTitle = "Ignored Facts Only"
else
   return
end
-- Process All Individuals and Family Events
recordTypes = {'INDI','FAM'}
ptr = fhNewItemPtr()
ptrEvent = fhNewItemPtr()
ptrDate  = fhNewItemPtr()
ptrWork  = fhNewItemPtr()
for k,recordType in pairs(recordTypes) do
ptr:MoveToFirstRecord(recordType)
while ptr:IsNotNull() do
   ptrEvent:MoveToFirstChildItem(ptr)
    while ptrEvent:IsNotNull() do
        if  fhIsFact(ptrEvent) then
			 ptrDate:MoveTo(ptrEvent,'~.DATE')
			 if ptrDate:IsNotNull() then
				i = 1
				warning = fhCallBuiltInFunction('GetDataWarning',ptrDate,i)
				
				while warning ~= "" do
					idx = getFactId(ptr,ptrEvent)
					bMarked = (Settings[idx] ~= nil)
					if (not(bMarked) or bIncludeMarks)   then
						if (not(bMarked) and not(bExcludeUnMarked)) or bMarked then
						table.insert(tblFact,ptrEvent:Clone())
						table.insert(tblReason,warning)
							if Settings[idx] ~= nil then
								table.insert(tblMarks,'X')
							else
								table.insert(tblMarks,' ')
							end
						if recordType == 'INDI' then
							table.insert(tblIndi,ptr:Clone())
							table.insert(tblSpouse,' ')
							ptrWork:MoveTo(ptr,'~.~FATH[1]>')
							table.insert(tblFather,ptrWork:Clone())
							ptrWork:MoveTo(ptr,'~.~MOTH[1]>')
							table.insert(tblMother,ptrWork:Clone())
						else
							ptrWork:MoveTo(ptr,'~.HUSB>')
							table.insert(tblIndi,ptrWork:Clone())
							ptrWork:MoveTo(ptr,'~.WIFE>')
							table.insert(tblSpouse,ptrWork:Clone())
							table.insert(tblFather,' ')
							table.insert(tblMother,' ')
						end
					end
					end
					i = i + 1 
				warning = fhCallBuiltInFunction('GetDataWarning',ptrDate,i)
				end
			end
		 end
	     ptrEvent:MoveNext('ANY')
    end
ptr:MoveNext("SAME_TAG")
end
end
-- Output Results
if #tblFact == 0 then
	fhMessageBox('No Unmarked Facts with Warnings Found')
else
	fhOutputResultSetTitles(strReportTitle.." - "..strReportSubTitle, strReportTitle, strReportSubTitle.." Date: %#x")

	if bIncludeMarks then
	fhOutputResultSetColumn("Marked", "text", tblMarks, #tblFact, 30, "align_mid")
	else

	end
	fhOutputResultSetColumn("Fact", "item", tblFact, #tblFact, 120, "align_left")
	fhOutputResultSetColumn("Warning", "text", tblReason, #tblFact, 200, "align_left")
	fhOutputResultSetColumn("Individual", "item", tblIndi, #tblFact, 120, "align_left")
	fhOutputResultSetColumn("Spouse", "item", tblSpouse, #tblFact, 120, "align_left")
	fhOutputResultSetColumn("Father", "item", tblFather, #tblFact, 120, "align_left")
	fhOutputResultSetColumn("Mother", "item", tblMother, #tblFact, 120, "align_left")

end


Source:Possible-Problem-Report1.fh_lua