1102 lines
40 KiB
OCaml
1102 lines
40 KiB
OCaml
open Def
|
|
open Gwdb
|
|
|
|
type base_error = person error
|
|
|
|
type base_warning =
|
|
(iper, person, ifam, family, title, pers_event, fam_event) warning
|
|
|
|
type base_misc = (person, family, title) misc
|
|
|
|
(* Constants used for computing the warnings. *)
|
|
let max_age_btw_cpl = 50
|
|
let max_days_btw_sibl = 10
|
|
let max_month_btw_sibl = 7
|
|
let lim_date_death = 1900
|
|
let max_death_after_lim_date_death = 105
|
|
let max_death_before_lim_date_death = 100
|
|
let min_parent_age = 11
|
|
let max_father_age = 70
|
|
let max_mother_age = 55
|
|
let min_age_marriage = 12
|
|
let max_age_marriage = 100
|
|
let max_siblings_gap = 50
|
|
|
|
(* Check if d1 < d2 *)
|
|
let strictly_before_dmy d1 d2 =
|
|
match Date.compare_dmy_opt ~strict:true d1 d2 with
|
|
| Some x -> x < 0
|
|
| None -> false
|
|
|
|
let strictly_before d1 d2 =
|
|
match (d1, d2) with
|
|
| Dgreg (d1, _), Dgreg (d2, _) -> strictly_before_dmy d1 d2
|
|
| _ -> false
|
|
|
|
let strictly_after_dmy d1 d2 =
|
|
match Date.compare_dmy_opt ~strict:true d1 d2 with
|
|
| Some x -> x > 0
|
|
| None -> false
|
|
|
|
let strictly_after d1 d2 =
|
|
match (d1, d2) with
|
|
| Dgreg (d1, _), Dgreg (d2, _) -> strictly_after_dmy d1 d2
|
|
| _ -> false
|
|
|
|
let strictly_younger age year =
|
|
match age.prec with
|
|
| After -> false
|
|
| Sure | About | Maybe | Before | OrYear _ | YearInt _ -> age.year < year
|
|
|
|
let strictly_older age year =
|
|
match age.prec with
|
|
| Before -> false
|
|
| Sure | About | Maybe | After | OrYear _ | YearInt _ -> age.year > year
|
|
|
|
let odate = function
|
|
| Some (Dgreg (d, _)) -> Some d
|
|
| Some (Dtext _) | None -> None
|
|
|
|
let obirth x = get_birth x |> Date.cdate_to_dmy_opt
|
|
|
|
let title_dates warning p t =
|
|
let t_date_start = Date.od_of_cdate t.t_date_start in
|
|
let t_date_end = Date.od_of_cdate t.t_date_end in
|
|
match (t_date_start, t_date_end) with
|
|
| None, None -> ()
|
|
| Some d1, Some d2 when strictly_after d1 d2 ->
|
|
warning (TitleDatesError (p, t))
|
|
| _ -> (
|
|
match Date.od_of_cdate (get_birth p) with
|
|
| None -> ()
|
|
| Some d1 -> (
|
|
match t_date_start with
|
|
| Some d ->
|
|
if strictly_after d1 d then warning (TitleDatesError (p, t))
|
|
| None -> (
|
|
match t_date_end with
|
|
| Some d ->
|
|
if strictly_after d1 d then warning (TitleDatesError (p, t))
|
|
| None -> ())))
|
|
|
|
let check_person_age warning p =
|
|
let aux d1 d2 =
|
|
Date.time_elapsed_opt d1 d2
|
|
|> Option.iter @@ fun a ->
|
|
if a.year < 0 then warning (BirthAfterDeath p)
|
|
else if d2.year > lim_date_death then (
|
|
if strictly_older a max_death_after_lim_date_death then
|
|
warning (DeadOld (p, a)))
|
|
else if strictly_older a max_death_before_lim_date_death then
|
|
warning (DeadOld (p, a))
|
|
in
|
|
(* On pourrait faire un calcul sur la descendance ou l'ascendance si *)
|
|
(* on ne trouve rien ... mais c'est peut être un peu trop gourmand *)
|
|
(* juste pour un warning ? *)
|
|
match Date.dmy_of_death (get_death p) with
|
|
| None -> ()
|
|
| Some d2 -> (
|
|
match Date.cdate_to_dmy_opt (get_birth p) with
|
|
| Some d -> aux d d2
|
|
| None -> (
|
|
match Date.cdate_to_dmy_opt (get_baptism p) with
|
|
| Some d -> aux d d2
|
|
| None -> ()))
|
|
|
|
let try_to_fix_relation_sex base warning p_ref =
|
|
let p_index = Some (get_iper p_ref) in
|
|
let fixed = ref 0 in
|
|
let not_fixed = ref 0 in
|
|
let changed_related =
|
|
List.fold_right
|
|
(fun ip changed_related ->
|
|
let p = poi base ip in
|
|
let rparents, changed, not_changed =
|
|
List.fold_right
|
|
(fun rel (rparents, changed, not_changed) ->
|
|
let rel, changed, not_changed =
|
|
match (p_index = rel.r_fath, p_index = rel.r_moth) with
|
|
| true, false ->
|
|
if get_sex p_ref = Female then
|
|
match rel.r_moth with
|
|
| Some ip ->
|
|
let oth_p = poi base ip in
|
|
if get_sex oth_p = Male then
|
|
let rel =
|
|
{ rel with r_fath = rel.r_moth; r_moth = p_index }
|
|
in
|
|
(rel, changed + 1, not_changed)
|
|
else (rel, changed, not_changed + 1)
|
|
| None ->
|
|
let rel =
|
|
{ rel with r_fath = None; r_moth = p_index }
|
|
in
|
|
(rel, changed + 1, not_changed)
|
|
else (rel, changed, not_changed)
|
|
| false, true ->
|
|
if get_sex p_ref = Male then
|
|
match rel.r_fath with
|
|
| Some ip ->
|
|
let oth_p = poi base ip in
|
|
if get_sex oth_p = Female then
|
|
let rel =
|
|
{ rel with r_moth = rel.r_fath; r_fath = p_index }
|
|
in
|
|
(rel, changed + 1, not_changed)
|
|
else (rel, changed, not_changed + 1)
|
|
| None ->
|
|
let rel =
|
|
{ rel with r_moth = None; r_fath = p_index }
|
|
in
|
|
(rel, changed + 1, not_changed)
|
|
else (rel, changed, not_changed)
|
|
| false, false -> (rel, changed, not_changed)
|
|
| true, true -> (rel, changed, not_changed + 1)
|
|
in
|
|
(rel :: rparents, changed, not_changed))
|
|
(get_rparents p) ([], 0, 0)
|
|
in
|
|
fixed := !fixed + changed;
|
|
not_fixed := !not_fixed + not_changed;
|
|
if changed > 0 then (ip, p, None, Some rparents) :: changed_related
|
|
else changed_related)
|
|
(get_related p_ref) []
|
|
in
|
|
warning (IncoherentSex (p_ref, !fixed, !not_fixed));
|
|
if !fixed > 0 then Some changed_related else None
|
|
|
|
let related_sex_is_coherent base warning p_ref =
|
|
let p_index = Some (get_iper p_ref) in
|
|
let merge_sex g1 g2 =
|
|
match (g1, g2) with
|
|
| Some Male, Some Male -> Some Male
|
|
| Some Female, Some Female -> Some Female
|
|
| Some Neuter, Some g -> Some g
|
|
| Some g, Some Neuter -> Some g
|
|
| _ -> None
|
|
in
|
|
let check_sex sex rparents =
|
|
List.fold_left
|
|
(fun g rel ->
|
|
match (p_index = rel.r_fath, p_index = rel.r_moth) with
|
|
| true, false -> merge_sex g (Some Male)
|
|
| false, true -> merge_sex g (Some Female)
|
|
| false, false -> g
|
|
| true, true -> None)
|
|
sex rparents
|
|
in
|
|
let new_sex =
|
|
List.fold_left
|
|
(fun g ip ->
|
|
let p = poi base ip in
|
|
check_sex g (get_rparents p))
|
|
(Some (get_sex p_ref))
|
|
(get_related p_ref)
|
|
in
|
|
match new_sex with
|
|
| Some g ->
|
|
if get_sex p_ref != g then Some [ (get_iper p_ref, p_ref, Some g, None) ]
|
|
else None
|
|
| None -> try_to_fix_relation_sex base warning p_ref
|
|
|
|
let check_difference_age_between_cpl warning fath moth =
|
|
let find_date p =
|
|
match Date.cdate_to_dmy_opt (get_birth p) with
|
|
| Some d -> Some d
|
|
| None -> (
|
|
match Date.cdate_to_dmy_opt (get_baptism p) with
|
|
| None -> None
|
|
| Some d -> Some d)
|
|
in
|
|
match find_date fath with
|
|
| None -> ()
|
|
| Some d1 -> (
|
|
match find_date moth with
|
|
| None -> ()
|
|
| Some d2 ->
|
|
(if d1.year < d2.year then Date.time_elapsed_opt d1 d2
|
|
else Date.time_elapsed_opt d2 d1)
|
|
|> Option.iter @@ fun a ->
|
|
if strictly_older a max_age_btw_cpl then
|
|
warning (BigAgeBetweenSpouses (fath, moth, a)))
|
|
|
|
(*
|
|
* Semi sort children by birth dates.
|
|
* If all children have birth dates, no problem.
|
|
* Otherwise, sorting groups of consecutive children who have dates.
|
|
* In not possible cases, try to keep order of children of same sex.
|
|
* ex: G1, B2 being resp. girl and boy with date(G1) < date(B2)
|
|
* and G and B begin resp. girls boys without dates
|
|
* if order is ... B2 B B B G1 ... it becomes ... G1 B2 B B B ...
|
|
* if order is ... B2 G G G G1 ... it becomes ... G G G G1 B2 ...
|
|
* if order is ... B2 G B G G1 ... no change (a warning appears).
|
|
*)
|
|
|
|
let semi_sort base a before comp di =
|
|
let rec loop i =
|
|
if i < 0 || i >= Array.length a then ()
|
|
else
|
|
let p1 = poi base a.(i) in
|
|
let d1 =
|
|
match Date.od_of_cdate (get_birth p1) with
|
|
| Some d1 -> Some d1
|
|
| None -> Date.od_of_cdate (get_baptism p1)
|
|
in
|
|
match d1 with
|
|
| Some d1 ->
|
|
let rec loop_j sex_interm_sib j =
|
|
if j < 0 || j >= Array.length a then loop (i + di)
|
|
else
|
|
let p2 = poi base a.(j) in
|
|
let d2 =
|
|
match Date.od_of_cdate (get_birth p2) with
|
|
| Some d2 -> Some d2
|
|
| None -> Date.od_of_cdate (get_baptism p2)
|
|
in
|
|
match d2 with
|
|
| Some d2 ->
|
|
if comp d1 d2 then
|
|
let j =
|
|
match sex_interm_sib with
|
|
| Some s ->
|
|
if s = get_sex p1 then None
|
|
else if s = get_sex p2 then Some j
|
|
else None
|
|
| None -> Some j
|
|
in
|
|
match j with
|
|
| Some j ->
|
|
let k =
|
|
let rec loop_k k =
|
|
if k < 0 || k >= Array.length a then k + di
|
|
else
|
|
let p3 = poi base a.(k) in
|
|
let d3 =
|
|
match Date.od_of_cdate (get_birth p3) with
|
|
| Some d3 -> Some d3
|
|
| None -> Date.od_of_cdate (get_baptism p3)
|
|
in
|
|
match d3 with
|
|
| Some d3 ->
|
|
if comp d1 d3 then loop_k (k - di) else k + di
|
|
| None -> k + di
|
|
in
|
|
loop_k (j - di)
|
|
in
|
|
(match !before with
|
|
| Some _ -> ()
|
|
| None -> before := Some (Array.copy a));
|
|
let ip = a.(i) in
|
|
(let rec loop_up j =
|
|
if j = k then ()
|
|
else (
|
|
a.(j) <- a.(j - di);
|
|
loop_up (j - di))
|
|
in
|
|
loop_up i);
|
|
a.(k) <- ip;
|
|
loop (i + di)
|
|
| None -> loop (i + di)
|
|
else loop (i + di)
|
|
| None -> (
|
|
match sex_interm_sib with
|
|
| Some s ->
|
|
if s = get_sex p2 then loop_j sex_interm_sib (j - di)
|
|
else loop (i + di)
|
|
| None -> loop_j (Some (get_sex p2)) (j - di))
|
|
in
|
|
loop_j None (i - di)
|
|
| None -> loop (i + di)
|
|
in
|
|
loop
|
|
|
|
let sort_children base children =
|
|
let before = ref None in
|
|
semi_sort base children before strictly_before 1 1;
|
|
semi_sort base children before strictly_after ~-1 1;
|
|
semi_sort base children before strictly_before 1 1;
|
|
match !before with Some b -> Some (b, children) | None -> None
|
|
|
|
let changed_marriages_order base warning p =
|
|
let b = Array.copy (get_family p) in
|
|
(* Astuce : on construire un tableau identique à la famille dans *)
|
|
(* lequel on remplace toutes les dates inconnues par la dernière *)
|
|
(* date maximale que l'on ait vu. *)
|
|
(* Exemple : Ma (mariage sans date), et M3 après M1 *)
|
|
(* ordre initial Ma M5 Mb M3 M1 ... devient Ma M1 M3 M5 Mb *)
|
|
let _, a =
|
|
Array.fold_left
|
|
(fun (max_date, tab) ifam ->
|
|
let fam = foi base ifam in
|
|
let date =
|
|
match Date.od_of_cdate (get_marriage fam) with
|
|
| Some d -> Some d
|
|
| None -> max_date
|
|
in
|
|
let max_date =
|
|
match (date, max_date) with
|
|
| Some d1, Some d2 ->
|
|
if Date.compare_date d1 d2 = 1 then Some d1 else Some d2
|
|
| Some d1, None -> Some d1
|
|
| _ -> max_date
|
|
in
|
|
(max_date, Array.append tab [| (ifam, date) |]))
|
|
(None, [||]) (get_family p)
|
|
in
|
|
Array.stable_sort
|
|
(fun (_f1, d1) (_f2, d2) ->
|
|
match (d1, d2) with Some d1, Some d2 -> Date.compare_date d1 d2 | _ -> 0)
|
|
a;
|
|
let a = Array.map (fun (f, _) -> f) a in
|
|
if a <> b then (
|
|
warning (ChangedOrderOfMarriages (p, b, a));
|
|
let rec loop i fam =
|
|
if i = Array.length fam then ()
|
|
else (
|
|
fam.(i) <- a.(i);
|
|
loop (i + 1) fam)
|
|
in
|
|
loop 0 (get_family p))
|
|
|
|
let close_siblings warning x np ifam =
|
|
match np with
|
|
| Some (elder, d1) -> (
|
|
match odate @@ Date.od_of_cdate (get_birth x) with
|
|
| None -> ()
|
|
| Some d2 ->
|
|
Date.time_elapsed_opt d1 d2
|
|
|> Option.iter @@ fun d ->
|
|
(* On vérifie les jumeaux ou naissances proches. *)
|
|
if
|
|
d.year = 0
|
|
&& d.month < max_month_btw_sibl
|
|
&& (d.month <> 0 || d.day >= max_days_btw_sibl)
|
|
then warning (CloseChildren (ifam, elder, x)))
|
|
| None -> ()
|
|
|
|
let born_after_his_elder_sibling warning x b np ifam des =
|
|
match np with
|
|
| None -> ()
|
|
| Some (elder, d1) -> (
|
|
match b with
|
|
| Some d2 ->
|
|
if strictly_after_dmy d1 d2 then
|
|
warning (ChildrenNotInOrder (ifam, des, elder, x))
|
|
| None -> (
|
|
match Date.dmy_of_death (get_death x) with
|
|
| None -> ()
|
|
| Some d2 ->
|
|
if strictly_after_dmy d1 d2 then
|
|
warning (ChildrenNotInOrder (ifam, des, elder, x))))
|
|
|
|
let siblings_gap gap child = function
|
|
| None -> gap
|
|
| Some b -> (
|
|
match gap with
|
|
| None -> Some ((b, child), (b, child))
|
|
| Some ((min, minp), (max, maxp)) ->
|
|
Some
|
|
( (if strictly_before_dmy b min then (b, child) else (min, minp)),
|
|
if strictly_after_dmy b max then (b, child) else (max, maxp) ))
|
|
|
|
let child_born_after_his_parent warning x parent =
|
|
match Date.cdate_to_dmy_opt (get_birth parent) with
|
|
| None -> ()
|
|
| Some g1 -> (
|
|
match Date.cdate_to_dmy_opt (get_birth x) with
|
|
| None -> (
|
|
match Date.dmy_of_death (get_death x) with
|
|
| None -> ()
|
|
| Some g2 ->
|
|
if strictly_after_dmy g1 g2 then
|
|
warning (ParentBornAfterChild (parent, x))
|
|
else
|
|
Date.time_elapsed_opt g1 g2
|
|
|> Option.iter @@ fun a ->
|
|
if strictly_younger a min_parent_age then
|
|
warning (ParentTooYoung (parent, a, x)))
|
|
| Some g2 ->
|
|
if strictly_after_dmy g1 g2 then
|
|
warning (ParentBornAfterChild (parent, x))
|
|
else
|
|
Date.time_elapsed_opt g1 g2
|
|
|> Option.iter @@ fun a ->
|
|
if strictly_younger a min_parent_age then
|
|
warning (ParentTooYoung (parent, a, x))
|
|
else if
|
|
(get_sex parent = Female && strictly_older a max_mother_age)
|
|
|| (get_sex parent = Male && strictly_older a max_father_age)
|
|
then warning (ParentTooOld (parent, a, x)))
|
|
|
|
let child_born_before_mother_death warning x mother =
|
|
match Date.cdate_to_dmy_opt (get_birth x) with
|
|
| None -> ()
|
|
| Some d1 -> (
|
|
match Date.dmy_of_death @@ get_death mother with
|
|
| None -> ()
|
|
| Some d2 ->
|
|
if strictly_after_dmy d1 d2 then
|
|
warning (MotherDeadBeforeChildBirth (mother, x)))
|
|
|
|
let possible_father warning x father =
|
|
match Date.cdate_to_dmy_opt (get_birth x) with
|
|
| Some d1 when d1.prec <> Before -> (
|
|
match Date.dmy_of_death (get_death father) with
|
|
| Some d2 when d2.prec <> After ->
|
|
let a2 =
|
|
match d2 with
|
|
| { prec = YearInt dmy2 } -> dmy2.year2
|
|
| { prec = OrYear dmy2 } -> dmy2.year2
|
|
| { year = a } -> a
|
|
in
|
|
if d1.year > a2 + 1 then warning (DeadTooEarlyToBeFather (father, x))
|
|
| Some _ | None -> ())
|
|
| Some _ | None -> ()
|
|
|
|
let child_has_sex warning child =
|
|
if get_sex child = Neuter then warning (UndefinedSex child)
|
|
|
|
(* this check if events chronology is sound (e.g. no baptism before birth *)
|
|
let check_order_pfevents get_name get_date warning events =
|
|
let events = Event.sort_events get_name get_date events in
|
|
let rec loop = function
|
|
| e1 :: e2 :: events -> (
|
|
match get_name e1 with
|
|
| Event.Pevent (Epers_Name _) | Event.Fevent (Efam_Name _) ->
|
|
loop (e2 :: events)
|
|
| n1 -> (
|
|
match get_name e2 with
|
|
| Event.Pevent (Epers_Name _) | Event.Fevent (Efam_Name _) ->
|
|
loop (e1 :: events)
|
|
| n2 ->
|
|
if Event.compare_event_name n1 n2 = 1 then
|
|
(* BUG:
|
|
- `sort_events` sorts events like points on a timeline
|
|
- date with precision (Before|After) are exlusive
|
|
so we can have this sorted list of events:
|
|
[ baptism at date n ; birth at date (Before n+1)]
|
|
which will raise an invalid warning *)
|
|
warning e1 e2;
|
|
loop (e2 :: events)))
|
|
| _l -> ()
|
|
in
|
|
loop events
|
|
|
|
let check_order_pevents warning p =
|
|
check_order_pfevents
|
|
(fun evt -> Event.Pevent evt.epers_name)
|
|
(fun evt -> evt.epers_date)
|
|
(fun e1 e2 -> warning (PEventOrder (p, e1, e2)))
|
|
(get_pevents p)
|
|
|
|
let check_order_fevents base warning fam =
|
|
let p = poi base (get_father fam) in
|
|
check_order_pfevents
|
|
(fun evt -> Event.Fevent evt.efam_name)
|
|
(fun evt -> evt.efam_date)
|
|
(fun e1 e2 -> warning (FEventOrder (p, e1, e2)))
|
|
(get_fevents fam)
|
|
|
|
let check_witness_pevents_aux warning origin evt date b d p witness_kind =
|
|
match (b, d) with
|
|
| Some (Dgreg (d1, _)), _ when strictly_before_dmy date d1 ->
|
|
warning (PWitnessEventBeforeBirth (p, evt, origin))
|
|
| _, Some (Dgreg (d3, _)) when strictly_after_dmy date d3 ->
|
|
if
|
|
witness_kind <> Def.Witness_Mentioned
|
|
&& witness_kind <> Def.Witness_Other
|
|
then warning (PWitnessEventAfterDeath (p, evt, origin))
|
|
| _ -> ()
|
|
|
|
let check_witness_pevents base warning origin =
|
|
List.iter
|
|
(fun evt ->
|
|
match Date.cdate_to_dmy_opt evt.epers_date with
|
|
| None -> ()
|
|
| Some d2 ->
|
|
Array.iter
|
|
(fun (iw, witness_kind) ->
|
|
let p = poi base iw in
|
|
check_witness_pevents_aux warning origin evt d2
|
|
(Date.od_of_cdate @@ get_birth p)
|
|
(Date.date_of_death @@ get_death p)
|
|
p witness_kind)
|
|
evt.epers_witnesses)
|
|
(get_pevents origin)
|
|
|
|
(** Returns wether [iper] can be found in the provided associative array and
|
|
wether it was found associated only with the Mentionned or Other witness kind.
|
|
**)
|
|
let witness_occur : iper -> (iper * witness_kind) array -> bool * bool =
|
|
let f iper (is_witness, only_mentioned_or_other) (i, wk) =
|
|
if i = iper then
|
|
( true,
|
|
only_mentioned_or_other
|
|
&& (wk = Def.Witness_Mentioned || wk = Def.Witness_Other) )
|
|
else (is_witness, only_mentioned_or_other)
|
|
in
|
|
fun iper a ->
|
|
let is_w, only_mentioned_or_other =
|
|
Array.fold_left (f iper) (false, true) a
|
|
in
|
|
(is_w, is_w && only_mentioned_or_other)
|
|
|
|
let witness_kind_of_witness_array iper witnesses =
|
|
let is_witness, only_mentioned_or_other = witness_occur iper witnesses in
|
|
if is_witness then
|
|
let kind =
|
|
if only_mentioned_or_other then Def.Witness_Mentioned else Def.Witness
|
|
in
|
|
Some kind
|
|
else None
|
|
|
|
let check_person_dates_as_witness base warning p =
|
|
let ip = get_iper p in
|
|
let aux date w1 w2 evt =
|
|
match Date.od_of_cdate (date evt) with
|
|
| Some (Dgreg (_, _) as d) -> (
|
|
(match Date.od_of_cdate (get_birth p) with
|
|
| Some (Dgreg (_, _) as d') -> if strictly_before d d' then w1 evt
|
|
| _ -> ());
|
|
match Date.date_of_death (get_death p) with
|
|
| Some d' -> if strictly_after d d' then w2 evt
|
|
| None -> ())
|
|
| Some (Dtext _) | None -> ()
|
|
in
|
|
let related_p = get_related p in
|
|
let related_fam =
|
|
List.fold_left
|
|
(fun acc ir ->
|
|
let r = poi base ir in
|
|
if get_sex r = Male then
|
|
Array.fold_left
|
|
(fun acc ifam ->
|
|
let fam = foi base ifam in
|
|
if Array.mem ip (get_witnesses fam) then fam :: acc else acc)
|
|
acc (get_family r)
|
|
else acc)
|
|
[] related_p
|
|
in
|
|
List.iter
|
|
(fun fam ->
|
|
List.iter
|
|
(fun evt ->
|
|
match witness_kind_of_witness_array ip evt.efam_witnesses with
|
|
| Some Def.Witness_Mentioned | Some Def.Witness_Other ->
|
|
aux
|
|
(fun e -> e.efam_date)
|
|
(fun e ->
|
|
warning (FWitnessEventBeforeBirth (p, e, get_ifam fam)))
|
|
(fun _ -> ())
|
|
evt
|
|
| Some _ ->
|
|
aux
|
|
(fun e -> e.efam_date)
|
|
(fun e ->
|
|
warning (FWitnessEventBeforeBirth (p, e, get_ifam fam)))
|
|
(fun e ->
|
|
warning (FWitnessEventAfterDeath (p, e, get_ifam fam)))
|
|
evt
|
|
| None -> ())
|
|
(get_fevents fam))
|
|
related_fam;
|
|
let related_pers =
|
|
List.fold_left
|
|
(fun acc ir ->
|
|
let r = poi base ir in
|
|
List.fold_left
|
|
(fun acc e ->
|
|
let witness_kind =
|
|
witness_kind_of_witness_array ip e.epers_witnesses
|
|
in
|
|
match witness_kind with
|
|
| Some kind -> (e, r, kind) :: acc
|
|
| _ -> acc)
|
|
acc (get_pevents r))
|
|
[] related_p
|
|
in
|
|
List.iter
|
|
(fun (evt, r, kind) ->
|
|
match kind with
|
|
| Def.Witness_Mentioned | Def.Witness_Other ->
|
|
aux
|
|
(fun e -> e.epers_date)
|
|
(fun e -> warning (PWitnessEventBeforeBirth (p, e, r)))
|
|
(fun _ -> ())
|
|
evt
|
|
| _ ->
|
|
aux
|
|
(fun e -> e.epers_date)
|
|
(fun e -> warning (PWitnessEventBeforeBirth (p, e, r)))
|
|
(fun e -> warning (PWitnessEventAfterDeath (p, e, r)))
|
|
evt)
|
|
related_pers
|
|
|
|
let check_pevents base warning p =
|
|
(* check order of events *)
|
|
check_order_pevents warning p;
|
|
(* check person's witnesses *)
|
|
check_witness_pevents base warning p;
|
|
(* check another witness dates where person is a witness *)
|
|
check_person_dates_as_witness base warning p
|
|
|
|
let check_siblings ?(onchange = true) base warning (ifam, fam) callback =
|
|
let children =
|
|
if onchange then (
|
|
let b = get_children fam in
|
|
match sort_children base b with
|
|
| None -> b
|
|
| Some (b, a) ->
|
|
warning (ChangedOrderOfChildren (ifam, fam, b, a));
|
|
a)
|
|
else get_children fam
|
|
in
|
|
let _, gap =
|
|
Array.fold_left
|
|
(fun (np, gap) child ->
|
|
let child = poi base child in
|
|
let b = obirth child in
|
|
let gap = siblings_gap gap child b in
|
|
born_after_his_elder_sibling warning child b np ifam fam;
|
|
close_siblings warning child np ifam;
|
|
callback child;
|
|
let np = match b with Some d -> Some (child, d) | _ -> np in
|
|
(np, gap))
|
|
(None, None) children
|
|
in
|
|
match gap with
|
|
| Some ((d1, p1), (d2, p2)) ->
|
|
Date.time_elapsed_opt d1 d2
|
|
|> Option.iter @@ fun e ->
|
|
if e.year > max_siblings_gap then
|
|
warning (DistantChildren (ifam, p1, p2))
|
|
| _ -> ()
|
|
|
|
let check_children ?(onchange = true) base warning (ifam, fam) fath moth =
|
|
check_siblings ~onchange base warning (ifam, fam) @@ fun child ->
|
|
check_pevents base warning child;
|
|
child_born_after_his_parent warning child fath;
|
|
child_born_after_his_parent warning child moth;
|
|
child_born_before_mother_death warning child moth;
|
|
possible_father warning child fath;
|
|
child_has_sex warning child
|
|
|
|
let has_family_sources fam =
|
|
not
|
|
(is_empty_string (get_fsources fam)
|
|
&& is_empty_string (get_marriage_src fam))
|
|
|
|
let has_person_sources p =
|
|
not
|
|
(is_empty_string (get_psources p)
|
|
&& is_empty_string (get_baptism_src p)
|
|
&& is_empty_string (get_birth_src p)
|
|
&& is_empty_string (get_death_src p)
|
|
&& is_empty_string (get_burial_src p))
|
|
|
|
(* ************************************************************************* *)
|
|
(* [Fonc] check_sources :
|
|
base -> (Def.misc -> unit) -> ifam -> family -> unit *)
|
|
|
|
(* ************************************************************************* *)
|
|
|
|
(** [Description] : Il y a un avertissment 'miscellaneous' si aucune des
|
|
personnes (conjoint1 ET conjoint2) n'a de sources
|
|
(indiduelles ou familliales).
|
|
[Args] :
|
|
- base : base
|
|
- misc : fonction qui ajoute un misc à la liste des miscs
|
|
- ifam : ifam
|
|
- fam : family
|
|
[Retour] : Néant
|
|
[Rem] : Non exporté en clair hors de ce module. *)
|
|
let check_sources base misc ifam fam =
|
|
if has_family_sources fam then ()
|
|
else
|
|
let cpl = foi base ifam in
|
|
let fath = poi base (get_father cpl) in
|
|
let moth = poi base (get_mother cpl) in
|
|
if has_person_sources fath && has_person_sources moth then ()
|
|
else misc MissingSources
|
|
|
|
let check_witness_fevents_aux warning fam evt date b d p witness_kind =
|
|
match (b, d) with
|
|
| Some (Dgreg (d1, _)), _ when strictly_before_dmy date d1 ->
|
|
warning (FWitnessEventBeforeBirth (p, evt, get_ifam fam))
|
|
| _, Some (Dgreg (d3, _)) when strictly_after_dmy date d3 ->
|
|
if
|
|
witness_kind <> Def.Witness_Mentioned
|
|
&& witness_kind <> Def.Witness_Other
|
|
then warning (FWitnessEventAfterDeath (p, evt, get_ifam fam))
|
|
| _ -> ()
|
|
|
|
let check_witness_fevents base warning fam =
|
|
List.iter
|
|
(fun evt ->
|
|
match Date.cdate_to_dmy_opt evt.efam_date with
|
|
| None -> ()
|
|
| Some d2 ->
|
|
Array.iter
|
|
(fun (iw, witness_kind) ->
|
|
let p = poi base iw in
|
|
check_witness_fevents_aux warning fam evt d2
|
|
(Date.od_of_cdate @@ get_birth p)
|
|
(Date.date_of_death @@ get_death p)
|
|
p witness_kind)
|
|
evt.efam_witnesses)
|
|
(get_fevents fam)
|
|
|
|
let check_parent_marriage_age warning fam p =
|
|
let rec loop = function
|
|
| [] -> ()
|
|
| { efam_name = Efam_Marriage | Efam_PACS; efam_date; _ } :: list -> (
|
|
match Date.od_of_cdate efam_date with
|
|
| Some (Dgreg (g2, _) as d2) -> (
|
|
match Date.date_of_death (get_death p) with
|
|
| Some d1 when strictly_after d2 d1 ->
|
|
warning (MarriageDateAfterDeath p)
|
|
| _ -> (
|
|
match Date.od_of_cdate (get_birth p) with
|
|
| Some (Dgreg (g1, _) as d1) ->
|
|
if strictly_before d2 d1 then
|
|
warning (MarriageDateBeforeBirth p)
|
|
else
|
|
Date.time_elapsed_opt g1 g2
|
|
|> Option.iter @@ fun e ->
|
|
if strictly_younger e min_age_marriage then
|
|
warning (YoungForMarriage (p, e, get_ifam fam))
|
|
else if strictly_older e max_age_marriage then
|
|
warning (OldForMarriage (p, e, get_ifam fam))
|
|
else loop list
|
|
| Some (Dtext _) | None -> loop list))
|
|
| _ -> loop list)
|
|
| _ :: list -> loop list
|
|
in
|
|
loop (get_fevents fam)
|
|
|
|
let check_possible_duplicate_family ?p base warning family father mother =
|
|
let ifath = get_father family in
|
|
let imoth = get_mother family in
|
|
let ifam = get_ifam family in
|
|
|
|
let name fn i = Name.strip_lower @@ sou base (fn i) in
|
|
let first_name = name get_first_name in
|
|
let surname = name get_surname in
|
|
|
|
let father_fn, father_sn = (first_name father, surname father) in
|
|
let mother_fn, mother_sn = (first_name mother, surname mother) in
|
|
let fath_families = get_family father in
|
|
let moth_families = get_family mother in
|
|
|
|
let f get_parent
|
|
( _current_parent,
|
|
current_parent_iper,
|
|
current_parent_fn,
|
|
current_parent_sn ) parent_source ifam' =
|
|
if eq_ifam ifam ifam' then ()
|
|
else
|
|
let fam' = foi base ifam' in
|
|
let parent' = get_parent fam' in
|
|
let person = poi base parent' in
|
|
let fn, sn = (first_name person, surname person) in
|
|
(* Parent is strictly the same *)
|
|
if eq_iper parent' current_parent_iper then
|
|
warning (PossibleDuplicateFam (ifam, ifam')) (* Homonymous parents *)
|
|
else if fn = current_parent_fn && sn = current_parent_sn then
|
|
warning (PossibleDuplicateFamHomonymous (ifam, ifam', parent_source))
|
|
else ()
|
|
in
|
|
|
|
match p with
|
|
| Some p when eq_iper (get_iper p) ifath ->
|
|
Array.iter
|
|
(f get_mother (mother, imoth, mother_fn, mother_sn) father)
|
|
fath_families
|
|
| Some p when eq_iper (get_iper p) imoth ->
|
|
Array.iter
|
|
(f get_father (father, ifath, father_fn, father_sn) mother)
|
|
moth_families
|
|
| _ ->
|
|
Array.iter
|
|
(f get_mother (mother, imoth, mother_fn, mother_sn) father)
|
|
fath_families;
|
|
Array.iter
|
|
(f get_father (father, ifath, father_fn, father_sn) mother)
|
|
moth_families
|
|
|
|
let check_parents base warning fam fath moth =
|
|
(* check father's marriage date *)
|
|
check_parent_marriage_age warning fam fath;
|
|
(* check mother's marriage date *)
|
|
check_parent_marriage_age warning fam moth;
|
|
(* check age difference between spouses *)
|
|
check_difference_age_between_cpl warning fath moth;
|
|
check_possible_duplicate_family base warning fam fath moth
|
|
|
|
let changed_pevents_order warning p =
|
|
let a = get_pevents p in
|
|
let b =
|
|
Event.sort_events
|
|
(fun evt -> Pevent evt.epers_name)
|
|
(fun evt -> evt.epers_date)
|
|
a
|
|
in
|
|
if a <> b then warning (ChangedOrderOfPersonEvents (p, a, b))
|
|
|
|
let changed_fevents_order warning (ifam, fam) =
|
|
let a =
|
|
Event.sort_events
|
|
(fun evt -> Fevent evt.efam_name)
|
|
(fun evt -> evt.efam_date)
|
|
(get_fevents fam)
|
|
in
|
|
let b = get_fevents fam in
|
|
if compare b a <> 0 then warning (ChangedOrderOfFamilyEvents (ifam, b, a))
|
|
|
|
(* main *)
|
|
|
|
let person ?(onchange = true) base warning p =
|
|
(* check personal events *)
|
|
check_pevents base warning p;
|
|
(* check person's age *)
|
|
check_person_age warning p;
|
|
(* check titles dates *)
|
|
List.iter (title_dates warning p) (get_titles p);
|
|
(* check order of personal events *)
|
|
if onchange then changed_pevents_order warning p;
|
|
related_sex_is_coherent base warning p
|
|
|
|
let family ?(onchange = true) base warning ifam fam =
|
|
let fath = poi base @@ get_father fam in
|
|
let moth = poi base @@ get_mother fam in
|
|
(* check order of familial events *)
|
|
check_order_fevents base warning fam;
|
|
(* check family's witnesses *)
|
|
check_witness_fevents base warning fam;
|
|
(* check parents marraige *)
|
|
check_parents base warning fam fath moth;
|
|
(* check children *)
|
|
check_children ~onchange base warning (ifam, fam) fath moth;
|
|
if onchange then (
|
|
changed_fevents_order warning (ifam, fam);
|
|
let father = poi base (get_father fam) in
|
|
let mother = poi base (get_mother fam) in
|
|
(* change order of father's families *)
|
|
changed_marriages_order base warning father;
|
|
(* change order of mother's families *)
|
|
changed_marriages_order base warning mother)
|
|
|
|
let check_related_person_pevents warning birth_date death_date p iper related_p
|
|
=
|
|
List.iter
|
|
(fun e ->
|
|
match Date.cdate_to_dmy_opt e.epers_date with
|
|
| None -> ()
|
|
| Some date ->
|
|
let is_witness, only_mentioned =
|
|
witness_occur iper e.epers_witnesses
|
|
in
|
|
if is_witness then
|
|
let witness_kind =
|
|
if only_mentioned then Def.Witness_Mentioned else Def.Witness
|
|
in
|
|
check_witness_pevents_aux warning related_p e date birth_date
|
|
death_date p witness_kind)
|
|
(get_pevents related_p)
|
|
|
|
let check_related_person_fevents warning base birth_date death_date p iper
|
|
related_p =
|
|
Array.iter
|
|
(fun i ->
|
|
let f = foi base i in
|
|
List.iter
|
|
(fun e ->
|
|
match Date.cdate_to_dmy_opt e.efam_date with
|
|
| None -> ()
|
|
| Some date ->
|
|
let is_witness, only_mentioned =
|
|
witness_occur iper e.efam_witnesses
|
|
in
|
|
if is_witness then
|
|
let witness_kind =
|
|
if only_mentioned then Def.Witness_Mentioned else Def.Witness
|
|
in
|
|
check_witness_fevents_aux warning f e date birth_date death_date
|
|
p witness_kind)
|
|
(get_fevents f))
|
|
(get_family related_p)
|
|
|
|
let check_related_on_person_update warning base birth_date death_date p iper
|
|
irel =
|
|
let related_p = poi base irel in
|
|
check_related_person_pevents warning birth_date death_date p iper related_p;
|
|
check_related_person_fevents warning base birth_date death_date p iper
|
|
related_p
|
|
|
|
let on_person_update base warning p =
|
|
(match get_parents p with
|
|
| Some i ->
|
|
let fam = foi base i in
|
|
let fath = poi base @@ get_father fam in
|
|
let moth = poi base @@ get_mother fam in
|
|
child_born_after_his_parent warning p fath;
|
|
child_born_after_his_parent warning p moth;
|
|
check_siblings base warning (i, fam) ignore
|
|
| None -> ());
|
|
let b = Date.od_of_cdate (get_birth p) in
|
|
let d = Date.date_of_death @@ get_death p in
|
|
let iper = get_iper p in
|
|
if b <> None || d <> None then
|
|
List.iter
|
|
(check_related_on_person_update warning base b d p iper)
|
|
(get_related p);
|
|
Array.iter
|
|
(fun ifam ->
|
|
let fam = foi base ifam in
|
|
let fath, moth =
|
|
if get_iper p = get_father fam then (p, poi base @@ get_mother fam)
|
|
else (poi base @@ get_father fam, p)
|
|
in
|
|
check_parent_marriage_age warning fam p;
|
|
check_difference_age_between_cpl warning fath moth;
|
|
check_possible_duplicate_family ~p base warning fam fath moth;
|
|
Array.iter
|
|
(fun child ->
|
|
let child = poi base child in
|
|
child_born_after_his_parent warning child p;
|
|
match get_sex p with
|
|
| Male -> possible_father warning child p
|
|
| Female -> child_born_before_mother_death warning child p
|
|
| Neuter -> ())
|
|
(get_children fam))
|
|
(get_family p)
|
|
|
|
(* ************************************************************************* *)
|
|
(* [Fonc] check_other_fields :
|
|
base -> (Def.misc -> unit) -> ifam -> family -> unit *)
|
|
|
|
(* ************************************************************************* *)
|
|
|
|
(** [Description] : Vérifie les autres champs de saisie des formulaires
|
|
individu et famille.
|
|
[Args] :
|
|
- base : base
|
|
- misc : fonction qui ajoute un misc à la liste des miscs
|
|
- ifam : ifam
|
|
- fam : family
|
|
[Retour] : Néant
|
|
[Rem] : Exporté en clair hors de ce module. *)
|
|
let check_other_fields base misc ifam fam = check_sources base misc ifam fam
|
|
|
|
let first_name base p = Name.strip_lower @@ sou base @@ get_first_name p
|
|
let surname base p = Name.strip_lower @@ sou base @@ get_surname p
|
|
|
|
let hom_person base p1 p2 =
|
|
let fn1, sn1 = (first_name base p1, surname base p1) in
|
|
let fn2, sn2 = (first_name base p2, surname base p2) in
|
|
fn1 = fn2 && sn1 = sn2
|
|
|
|
let hom_fam base f1 f2 =
|
|
let f1, f2 = (foi base f1, foi base f2) in
|
|
let fa1, mo1 = (poi base @@ get_father f1, poi base @@ get_mother f1) in
|
|
let fa2, mo2 = (poi base @@ get_father f2, poi base @@ get_mother f2) in
|
|
hom_person base fa1 fa2 && hom_person base mo1 mo2
|
|
|
|
let eq_person p1 p2 = eq_iper (get_iper p1) (get_iper p2)
|
|
let eq_family f1 f2 = eq_ifam (get_ifam f1) (get_ifam f2)
|
|
|
|
let eq_warning base w1 w2 =
|
|
match (w1, w2) with
|
|
| PossibleDuplicateFam (f1, f2), PossibleDuplicateFam (f1', f2') ->
|
|
(eq_ifam f1 f1' && eq_ifam f2 f2') || (eq_ifam f1 f2' && eq_ifam f2 f1')
|
|
| ( PossibleDuplicateFamHomonymous (f1, f2, _),
|
|
PossibleDuplicateFamHomonymous (f1', f2', _) ) ->
|
|
(hom_fam base f1 f1' && hom_fam base f2 f2')
|
|
|| (hom_fam base f1 f2' && hom_fam base f2 f1')
|
|
| BigAgeBetweenSpouses (p1, p2, d), BigAgeBetweenSpouses (p1', p2', d') ->
|
|
((eq_person p1 p1' && eq_person p2 p2')
|
|
|| (eq_person p1 p2' && eq_person p2 p1'))
|
|
&& d = d'
|
|
| BirthAfterDeath p, BirthAfterDeath p' -> eq_person p p'
|
|
| IncoherentSex (p, s1, s2), IncoherentSex (p', s1', s2') ->
|
|
eq_person p p' && ((s1 = s1' && s2 = s2') || (s1 = s2' && s2 = s1'))
|
|
| ( ChangedOrderOfChildren (ifam, fam, ipers1, ipers2),
|
|
ChangedOrderOfChildren (ifam', fam', ipers1', ipers2') ) ->
|
|
eq_ifam ifam ifam' && eq_family fam fam' && ipers1 = ipers1'
|
|
&& ipers2 = ipers2'
|
|
| ( ChangedOrderOfMarriages (p, ifams, ifams2),
|
|
ChangedOrderOfMarriages (p', ifams', ifams2') ) ->
|
|
eq_person p p' && ifams = ifams' && ifams2 = ifams2'
|
|
| ( ChangedOrderOfFamilyEvents (ifam, fevents, fevents2),
|
|
ChangedOrderOfFamilyEvents (ifam', fevents', fevents2') ) ->
|
|
eq_ifam ifam ifam' && fevents = fevents' && fevents2 = fevents2'
|
|
| ( ChangedOrderOfPersonEvents (p, pevents, pevents2),
|
|
ChangedOrderOfPersonEvents (p', pevents', pevents2') ) ->
|
|
eq_person p p' && pevents = pevents' && pevents2 = pevents2'
|
|
| ( ChildrenNotInOrder (ifam, fam, p1, p2),
|
|
ChildrenNotInOrder (ifam', fam', p1', p2') ) ->
|
|
eq_ifam ifam ifam' && eq_family fam fam' && eq_person p1 p1'
|
|
&& eq_person p2 p2'
|
|
| CloseChildren (ifam, p1, p2), CloseChildren (ifam', p1', p2') ->
|
|
eq_ifam ifam ifam'
|
|
&& ((eq_person p1 p1' && eq_person p2 p2')
|
|
|| (eq_person p1 p2' && eq_person p2 p1'))
|
|
| DeadOld (p, d), DeadOld (p', d') -> eq_person p p' && d = d'
|
|
| DeadTooEarlyToBeFather (p1, p2), DeadTooEarlyToBeFather (p1', p2') ->
|
|
eq_person p1 p1' && eq_person p2 p2'
|
|
| DistantChildren (ifam, p1, p2), DistantChildren (ifam', p1', p2') ->
|
|
eq_ifam ifam ifam' && eq_person p1 p1' && eq_person p2 p2'
|
|
| FEventOrder (p, fevent, fevent2), FEventOrder (p', fevent', fevent2') ->
|
|
eq_person p p' && fevent = fevent' && fevent2 = fevent2'
|
|
| ( FWitnessEventAfterDeath (p, fevent, ifam),
|
|
FWitnessEventAfterDeath (p', fevent', ifam') ) ->
|
|
eq_person p p' && fevent = fevent' && eq_ifam ifam ifam'
|
|
| ( FWitnessEventBeforeBirth (p, fevent, ifam),
|
|
FWitnessEventBeforeBirth (p', fevent', ifam') ) ->
|
|
eq_person p p' && fevent = fevent' && eq_ifam ifam ifam'
|
|
| IncoherentAncestorDate (p1, p2), IncoherentAncestorDate (p1', p2') ->
|
|
eq_person p1 p1' && eq_person p2 p2'
|
|
| MarriageDateAfterDeath p, MarriageDateAfterDeath p' -> eq_person p p'
|
|
| MarriageDateBeforeBirth p, MarriageDateBeforeBirth p' -> eq_person p p'
|
|
| MotherDeadBeforeChildBirth (p1, p2), MotherDeadBeforeChildBirth (p1', p2')
|
|
->
|
|
eq_person p1 p1' && eq_person p2 p2'
|
|
| ParentBornAfterChild (p1, p2), ParentBornAfterChild (p1', p2') ->
|
|
eq_person p1 p1' && eq_person p2 p2'
|
|
| ParentTooOld (p1, d, p2), ParentTooOld (p1', d', p2') ->
|
|
eq_person p1 p1' && eq_person p2 p2' && d = d'
|
|
| ParentTooYoung (p1, d, p2), ParentTooYoung (p1', d', p2') ->
|
|
eq_person p1 p1' && eq_person p2 p2' && d = d'
|
|
| PEventOrder (p, pevent1, pevent2), PEventOrder (p', pevent1', pevent2') ->
|
|
eq_person p p' && pevent1 = pevent1' && pevent2 = pevent2'
|
|
| ( PWitnessEventAfterDeath (p1, pevent, p2),
|
|
PWitnessEventAfterDeath (p1', pevent', p2') ) ->
|
|
eq_person p1 p1' && eq_person p2 p2' && pevent = pevent'
|
|
| ( PWitnessEventBeforeBirth (p1, pevent, p2),
|
|
PWitnessEventBeforeBirth (p1', pevent', p2') ) ->
|
|
eq_person p1 p1' && eq_person p2 p2' && pevent = pevent'
|
|
| TitleDatesError (p, title), TitleDatesError (p', title') ->
|
|
eq_person p p' && title = title'
|
|
| UndefinedSex p, UndefinedSex p' -> eq_person p p'
|
|
| YoungForMarriage (p, d, ifam), YoungForMarriage (p', d', ifam') ->
|
|
eq_person p p' && d = d' && eq_ifam ifam ifam'
|
|
| OldForMarriage (p, d, ifam), OldForMarriage (p', d', ifam') ->
|
|
eq_person p p' && d = d' && eq_ifam ifam ifam'
|
|
| _ -> false
|
|
|
|
let person_warnings conf base p =
|
|
let w = ref [] in
|
|
let filter x =
|
|
if
|
|
(not (List.exists (eq_warning base x) !w))
|
|
&& Util.auth_warning conf base x
|
|
then w := x :: !w
|
|
in
|
|
ignore @@ person base filter p;
|
|
on_person_update base filter p;
|
|
Array.iter
|
|
(fun ifam ->
|
|
check_siblings ~onchange:false base filter (ifam, foi base ifam) ignore)
|
|
(get_family p);
|
|
!w
|