(* camlp4r ./pa_html.cmo ./pa_lock.cmo *)
(* $Id: mergeInd.ml,v 4.26.2.1 2006/01/03 12:04:10 ddr Exp $ *)
(* Copyright (c) 1998-2005 INRIA *)
open Config;
open Def;
open Util;
open Gutil;
value print_differences conf base branches p1 p2 =
let gen_string_field chk1 chk2 str_orig title name proj =
let x1 = proj p1 in
let x2 = proj p2 in
if x1 <> "" && x1 <> "?" && x2 <> "" && x2 <> "?" && x1 <> x2 then do {
Wserver.wprint "
%s
\n" (capitale title);
tag "ul" begin
html_li conf;
Wserver.wprint "\n" name chk1;
Wserver.wprint "%s\n" x1;
html_li conf;
Wserver.wprint "\n" name chk2;
Wserver.wprint "%s\n" x2;
end;
}
else ()
in
let string_field = gen_string_field " checked" "" in
tag "form" "method=POST action=\"%s\"" conf.command begin
Util.hidden_env conf;
Wserver.wprint "\n";
Wserver.wprint "\n"
(Adef.int_of_iper p1.cle_index);
Wserver.wprint "\n"
(Adef.int_of_iper p2.cle_index);
loop branches where rec loop =
fun
[ [(ip1, ip2)] ->
do {
Wserver.wprint "\n"
(Adef.int_of_iper ip1);
Wserver.wprint "\n"
(Adef.int_of_iper ip2);
}
| [_ :: branches] -> loop branches
| _ -> () ];
html_p conf;
string_field True (transl_nth conf "first name/first names" 0)
"first_name" (fun p -> p_first_name base p);
string_field True (transl_nth conf "surname/surnames" 0) "surname"
(fun p -> p_surname base p);
let select_smallest_num = p_first_name base p1 = p_first_name base p2 in
gen_string_field
(if p1.occ < p2.occ || not select_smallest_num then " checked" else "")
(if p1.occ > p2.occ && select_smallest_num then " checked" else "")
False (transl conf "number") "number" (fun p -> string_of_int p.occ);
string_field True (transl_nth conf "image/images" 0) "image"
(fun p -> sou base p.image);
string_field True (transl conf "public name") "public_name"
(fun p -> sou base p.public_name);
string_field True (transl conf "occupation") "occupation"
(fun p -> sou base p.occupation);
string_field False (transl conf "sex") "sex"
(fun p ->
match p.sex with
[ Male -> "M"
| Female -> "F"
| Neuter -> "" ]);
(*
string_field False (transl conf "access") "access"
(fun p ->
match p.access with
[ IfTitles -> transl conf "if titles"
| Private -> "private"
| Public -> "public" ]);
*)
string_field False (transl conf "birth") "birth"
(fun p ->
match Adef.od_of_codate p.birth with
[ None -> ""
| Some d -> Date.string_of_ondate conf d ]);
string_field True (transl conf "birth" ^ " / " ^ transl conf "place")
"birth_place" (fun p -> sou base p.birth_place);
string_field False (transl conf "baptism") "baptism"
(fun p ->
match Adef.od_of_codate p.baptism with
[ None -> ""
| Some d -> Date.string_of_ondate conf d ]);
string_field True (transl conf "baptism" ^ " / " ^ transl conf "place")
"baptism_place" (fun p -> sou base p.baptism_place);
string_field False (transl conf "death") "death"
(fun p ->
let is = 2 in
match p.death with
[ NotDead -> transl_nth conf "alive" is
| Death dr cd ->
let s =
match dr with
[ Killed -> transl_nth conf "killed (in action)" is
| Murdered -> transl_nth conf "murdered" is
| Executed -> transl_nth conf "executed (legally killed)" is
| Disappeared -> transl_nth conf "disappeared" is
| Unspecified -> transl_nth conf "died" is ]
in
s ^ " " ^ Date.string_of_ondate conf (Adef.date_of_cdate cd)
| DeadYoung -> transl_nth conf "died young" is
| DeadDontKnowWhen -> transl_nth conf "died" is
| DontKnowIfDead -> "" ]);
string_field True (transl conf "death" ^ " / " ^ transl conf "place")
"death_place" (fun p -> sou base p.death_place);
string_field False (transl conf "burial") "burial"
(fun p ->
let is = 2 in
match p.burial with
[ UnknownBurial -> ""
| Buried cod ->
transl_nth conf "buried" is ^
(match Adef.od_of_codate cod with
[ None -> ""
| Some d -> " " ^ Date.string_of_ondate conf d ])
| Cremated cod ->
transl_nth conf "cremated" is ^
(match Adef.od_of_codate cod with
[ None -> ""
| Some d -> " " ^ Date.string_of_ondate conf d ]) ]);
string_field True (transl conf "burial" ^ " / " ^ transl conf "place")
"burial_place" (fun p -> sou base p.burial_place);
html_p conf;
Wserver.wprint "\n";
end
;
value compatible_codates cd1 cd2 =
cd1 = cd2 || cd2 = Adef.codate_None || cd1 = Adef.codate_None;
value compatible_cdates cd1 cd2 = cd1 = cd2;
value compatible_death_reasons dr1 dr2 = dr1 = dr2 || dr2 = Unspecified;
value compatible_deaths d1 d2 =
if d1 = d2 then True
else
match (d1, d2) with
[ (Death dr1 cd1, Death dr2 cd2) ->
compatible_death_reasons dr1 dr2 && compatible_cdates cd1 cd2
| (Death _ _, NotDead) -> False
| (Death _ _, _) -> True
| (_, DontKnowIfDead) -> True
| (DontKnowIfDead, _) -> True
| _ -> False ]
;
value compatible_burials b1 b2 =
if b1 = b2 then True
else
match (b1, b2) with
[ (_, UnknownBurial) -> True
| (UnknownBurial, _) -> True
| (Buried cd1, Buried cd2) -> compatible_codates cd1 cd2
| (Cremated cd1, Cremated cd2) -> compatible_codates cd1 cd2
| _ -> False ]
;
value compatible_strings s1 s2 =
s1 = s2 || s2 = Adef.istr_of_int 0 || s1 = Adef.istr_of_int 0;
value compatible_divorces d1 d2 = d1 = d2;
value compatible_relation_kinds rk1 rk2 = rk1 = rk2;
value compatible_accesses a1 a2 = (*a1 = a2*)True;
value compatible_titles t1 t2 = t1 = t2 || t2 = [];
value compatible_strings_lists sl1 sl2 = sl2 = [] || sl1 = sl2;
value compatible_ind base p1 p2 =
p1.first_name = p2.first_name && p1.surname = p2.surname &&
compatible_strings p1.image p2.image &&
compatible_strings p1.public_name p2.public_name &&
compatible_strings_lists p1.qualifiers p2.qualifiers &&
compatible_strings_lists p1.aliases p2.aliases &&
compatible_strings_lists p1.first_names_aliases p2.first_names_aliases &&
compatible_strings_lists p1.surnames_aliases p2.surnames_aliases &&
compatible_titles p1.titles p2.titles && p2.rparents = [] &&
p2.related = [] && compatible_strings p1.occupation p2.occupation &&
compatible_accesses p1.access p2.access &&
compatible_codates p1.birth p2.birth &&
compatible_strings p1.birth_place p2.birth_place &&
compatible_codates p1.baptism p2.baptism &&
compatible_strings p1.baptism_place p2.baptism_place &&
compatible_deaths p1.death p2.death &&
compatible_strings p1.death_place p2.death_place &&
compatible_burials p1.burial p2.burial &&
compatible_strings p1.burial_place p2.burial_place &&
compatible_strings p1.notes p2.notes
(*
&&
compatible_strings p1.psources p2.psources
*)
;
value compatible_fam base fam1 fam2 =
compatible_codates fam1.marriage fam2.marriage &&
compatible_strings fam1.marriage_place fam2.marriage_place &&
Array.length fam2.witnesses = 0 &&
compatible_relation_kinds fam1.relation fam2.relation &&
compatible_divorces fam1.divorce fam2.divorce &&
compatible_strings fam1.fsources fam2.fsources
;
value propose_merge_ind conf base branches p1 p2 =
let title h =
let s = transl_nth conf "person/persons" 1 in
Wserver.wprint "%s" (capitale (transl_decline conf "merge" s))
in
do {
header conf title;
if branches <> [] then do {
Wserver.wprint "%s:\n" (capitale (transl conf "you must first merge"));
tag "ul" begin
html_li conf;
stag "a" "href=\"%s%s\"" (commd conf) (acces conf base p1) begin
Merge.print_someone conf base p1;
end;
Wserver.wprint "\n%s\n" (transl_nth conf "and" 0);
stag "a" "href=\"%s%s\"" (commd conf) (acces conf base p2) begin
Merge.print_someone conf base p2;
end;
Wserver.wprint "\n";
end;
html_p conf;
}
else ();
print_differences conf base branches p1 p2;
if branches <> [] then do {
html_p conf;
Wserver.wprint "";
html_p conf;
Wserver.wprint "%s:\n" (capitale (transl_nth conf "branch/branches" 1));
html_p conf;
tag "table" begin
List.iter
(fun (ip1, ip2) ->
let p1 = poi base ip1 in
let p2 = poi base ip2 in
do {
tag "tr" "align=left" begin
tag "td" begin
Wserver.wprint "\n%s" (referenced_person_text conf base p1);
Wserver.wprint "%s" (Date.short_dates_text conf base p1);
end;
tag "td" begin
Wserver.wprint "\n%s" (referenced_person_text conf base p2);
Wserver.wprint "%s" (Date.short_dates_text conf base p2);
end;
end;
})
[(p1.cle_index, p2.cle_index) :: branches];
end;
}
else ();
trailer conf;
}
;
value reparent_ind base p1 p2 =
let a1 = aoi base p1.cle_index in
let a2 = aoi base p2.cle_index in
match (parents a1, parents a2) with
[ (None, Some ifam) ->
let des = doi base ifam in
do {
let rec replace i =
if des.children.(i) = p2.cle_index then
des.children.(i) := p1.cle_index
else replace (i + 1)
in
replace 0;
set_parents a1 (Some ifam);
set_consang a1 (Adef.fix (-1));
base.func.patch_ascend p1.cle_index a1;
base.func.patch_descend ifam des;
}
| _ -> () ]
;
value effective_merge_ind conf base p1 p2 =
do {
reparent_ind base p1 p2;
let u2 = uoi base p2.cle_index in
if Array.length u2.family <> 0 then do {
for i = 0 to Array.length u2.family - 1 do {
let ifam = u2.family.(i) in
let cpl = coi base ifam in
if p2.cle_index = (father cpl) then set_father cpl p1.cle_index
else if p2.cle_index = (mother cpl) then set_mother cpl p1.cle_index
else assert False;
base.func.patch_couple ifam cpl;
};
let u1 = uoi base p1.cle_index in
u1.family := Array.append u1.family u2.family;
base.func.patch_union p1.cle_index u1;
u2.family := [| |];
base.func.patch_union p2.cle_index u2;
}
else ();
if p2.sex <> Neuter then p1.sex := p2.sex else ();
if p1.birth = Adef.codate_None then p1.birth := p2.birth else ();
if p1.birth_place = Adef.istr_of_int 0 then
p1.birth_place := p2.birth_place
else ();
if p1.birth_src = Adef.istr_of_int 0 then
p1.birth_src := p2.birth_src
else ();
if p1.baptism = Adef.codate_None then p1.baptism := p2.baptism else ();
if p1.baptism_place = Adef.istr_of_int 0 then
p1.baptism_place := p2.baptism_place
else ();
if p1.baptism_src = Adef.istr_of_int 0 then
p1.baptism_src := p2.baptism_src
else ();
if p1.death = DontKnowIfDead then p1.death := p2.death else ();
if p1.death_place = Adef.istr_of_int 0 then
p1.death_place := p2.death_place
else ();
if p1.death_src = Adef.istr_of_int 0 then
p1.death_src := p2.death_src
else ();
if p1.burial = UnknownBurial then p1.burial := p2.burial else ();
if p1.burial_place = Adef.istr_of_int 0 then
p1.burial_place := p2.burial_place
else ();
if p1.burial_src = Adef.istr_of_int 0 then
p1.burial_src := p2.burial_src
else ();
if p1.occupation = Adef.istr_of_int 0 then
p1.occupation := p2.occupation
else ();
if p1.notes = Adef.istr_of_int 0 then p1.notes := p2.notes else ();
UpdateIndOk.effective_del conf base p2;
base.func.patch_person p1.cle_index p1;
base.func.patch_person p2.cle_index p2;
}
;
value merge_ind conf base branches ip1 ip2 changes_done =
let p1 = poi base ip1 in
let p2 = poi base ip2 in
if compatible_ind base p1 p2 then do {
effective_merge_ind conf base p1 p2; (True, True)
}
else do {
propose_merge_ind conf base branches p1 p2; (False, changes_done)
}
;
value propose_merge_fam conf base branches fam1 fam2 p1 p2 =
let title h =
let s = transl_nth conf "family/families" 1 in
Wserver.wprint "%s" (capitale (transl_decline conf "merge" s))
in
do {
header conf title;
Wserver.wprint "%s:\n"
(capitale (transl conf "you must first merge the 2 families"));
tag "ul" begin
html_li conf;
stag "a" "href=\"%s%s\"" (commd conf) (acces conf base p1) begin
Merge.print_someone conf base p1;
end;
Wserver.wprint "\n%s\n" (transl conf "with");
stag "a" "href=\"%s%s\"" (commd conf) (acces conf base p2) begin
Merge.print_someone conf base p2;
end;
Wserver.wprint "\n";
end;
html_p conf;
MergeFam.print_differences conf base branches fam1 fam2;
trailer conf;
}
;
value effective_merge_fam conf base fam1 fam2 p1 p2 =
let des1 = doi base fam1.fam_index in
let des2 = doi base fam2.fam_index in
do {
if fam1.marriage = Adef.codate_None then fam1.marriage := fam2.marriage
else ();
if fam1.marriage_place = Adef.istr_of_int 0 then
fam1.marriage_place := fam2.marriage_place
else ();
if fam1.marriage_src = Adef.istr_of_int 0 then
fam1.marriage_src := fam2.marriage_src
else ();
if fam1.fsources = Adef.istr_of_int 0 then
fam1.fsources := fam2.fsources
else ();
base.func.patch_family fam1.fam_index fam1;
des1.children := Array.append des1.children des2.children;
base.func.patch_descend fam1.fam_index des1;
for i = 0 to Array.length des2.children - 1 do {
let ip = des2.children.(i) in
let a = aoi base ip in
set_parents a (Some fam1.fam_index);
base.func.patch_ascend ip a;
};
des2.children := [| |];
base.func.patch_descend fam2.fam_index des2;
UpdateFamOk.effective_del conf base fam2;
}
;
value merge_fam conf base branches ifam1 ifam2 ip1 ip2 changes_done =
let p1 = poi base ip1 in
let p2 = poi base ip2 in
let fam1 = foi base ifam1 in
let fam2 = foi base ifam2 in
if compatible_fam base fam1 fam2 then do {
effective_merge_fam conf base fam1 fam2 p1 p2; (True, True)
}
else do {
propose_merge_fam conf base branches fam1 fam2 p1 p2;
(False, changes_done)
}
;
value not_found_or_incorrect conf =
let title _ = Wserver.wprint "%s" (capitale (transl conf "error")) in
do {
rheader conf title;
Wserver.wprint "%s %s %s %s %s\n" (capitale (transl conf "not found"))
(transl conf "or") (transl conf "several answers") (transl conf "or")
(transl conf "incorrect request");
trailer conf;
}
;
value same_person conf =
let title _ = Wserver.wprint "%s" (capitale (transl conf "error")) in
do {
rheader conf title;
Wserver.wprint "%s\n" (capitale (transl conf "it is the same person!"));
trailer conf;
}
;
value different_sexes conf =
let title _ = Wserver.wprint "%s" (capitale (transl conf "error")) in
do {
rheader conf title;
Wserver.wprint "%s.\n" (capitale (transl conf "incompatible sexes"));
trailer conf;
}
;
value rec try_merge conf base branches ip1 ip2 changes_done =
let a1 = aoi base ip1 in
let a2 = aoi base ip2 in
let ok_so_far = True in
let (ok_so_far, changes_done) =
match (parents a1, parents a2) with
[ (Some ifam1, Some ifam2) when ifam1 <> ifam2 ->
let branches = [(ip1, ip2) :: branches] in
let cpl1 = coi base ifam1 in
let cpl2 = coi base ifam2 in
let (ok_so_far, changes_done) =
if ok_so_far then
if (father cpl1) = (father cpl2) then (True, changes_done)
else
try_merge conf base branches (father cpl1) (father cpl2)
changes_done
else (False, changes_done)
in
let (ok_so_far, changes_done) =
if ok_so_far then
if (mother cpl1) = (mother cpl2) then (True, changes_done)
else
try_merge conf base branches (mother cpl1) (mother cpl2)
changes_done
else (False, changes_done)
in
let (ok_so_far, changes_done) =
if ok_so_far then
merge_fam conf base branches ifam1 ifam2 (father cpl1) (mother cpl1)
changes_done
else (False, changes_done)
in
(ok_so_far, changes_done)
| _ -> (ok_so_far, changes_done) ]
in
if ok_so_far then merge_ind conf base branches ip1 ip2 changes_done
else (False, changes_done)
;
value print_merged conf base p =
let title _ = Wserver.wprint "%s" (capitale (transl conf "merge done")) in
do {
header conf title;
print_link_to_welcome conf True;
Wserver.wprint "\n%s" (referenced_person_text conf base p);
Wserver.wprint "\n";
trailer conf;
}
;
value is_ancestor base ip1 ip2 =
let visited = Array.create base.data.persons.len False in
let rec loop ip =
if visited.(Adef.int_of_iper ip) then False
else if ip = ip1 then True
else do {
visited.(Adef.int_of_iper ip) := True;
match parents (aoi base ip) with
[ Some ifam ->
let cpl = coi base ifam in loop (father cpl) || loop (mother cpl)
| None -> False ]
}
in
loop ip2
;
value error_loop conf base p =
let title _ = Wserver.wprint "%s" (capitale (transl conf "error")) in
do {
rheader conf title;
print_link_to_welcome conf True;
Wserver.wprint "%s%s %s" (p_first_name base p)
(if p.occ = 0 then "" else "." ^ string_of_int p.occ)
(p_surname base p);
Wserver.wprint "\n%s\n" (transl conf "would be his/her own ancestor");
Wserver.wprint "\n";
trailer conf;
}
;
value print conf base =
let p1 =
match p_getint conf.env "i" with
[ Some i1 -> Some (base.data.persons.get i1)
| None -> None ]
in
let p2 =
match p_getint conf.env "i2" with
[ Some i2 -> Some (base.data.persons.get i2)
| None ->
match (p_getenv conf.env "select", p_getenv conf.env "n") with
[ (Some "input" | None, Some n) ->
let ipl = Gutil.person_ht_find_all base n in
match ipl with
[ [ip2] -> Some (poi base ip2)
| _ -> None ]
| (Some x, Some "" | None) ->
Some (base.data.persons.get (int_of_string x))
| _ -> None ] ]
in
match (p1, p2) with
[ (Some p1, Some p2) ->
if p1.cle_index = p2.cle_index then same_person conf
else if p1.sex <> p2.sex && p1.sex <> Neuter && p2.sex <> Neuter then
different_sexes conf
else if is_ancestor base p1.cle_index p2.cle_index then
error_loop conf base p2
else if is_ancestor base p2.cle_index p1.cle_index then
error_loop conf base p1
else
(*
let bfile = Util.base_path [] (conf.bname ^ ".gwb") in
lock (Iobase.lock_file bfile) with
[ Accept ->
*)
let (ok, changes_done) =
try_merge conf base [] p1.cle_index p2.cle_index False
in
do {
if changes_done then Util.commit_patches conf base else ();
if ok then do {
let key =
(sou base p1.first_name, sou base p1.surname, p1.occ)
in
History.record conf base key "fp";
print_merged conf base p1;
}
else ();
}
(*
| Refuse -> Update.error_locked conf base ]
*)
| _ -> not_found_or_incorrect conf ]
;
(* Undocumented feature... Kill someone's ancestors *)
value rec kill_ancestors conf base included_self p nb_ind nb_fam =
do {
match parents (aoi base p.cle_index) with
[ Some ifam ->
let cpl = coi base ifam in
do {
kill_ancestors conf base True (poi base (father cpl)) nb_ind nb_fam;
kill_ancestors conf base True (poi base (mother cpl)) nb_ind nb_fam;
UpdateFamOk.effective_del conf base (foi base ifam);
incr nb_fam;
}
| None -> () ];
if included_self then do {
let ip = p.cle_index in
UpdateIndOk.effective_del conf base p;
base.func.patch_person ip p;
incr nb_ind;
}
else ();
}
;
value print_killed conf base p nb_ind nb_fam =
let title _ = Wserver.wprint "Ancestors killed" in
do {
Util.header conf title;
Wserver.wprint "%s's ancestors killed. \n"
(referenced_person_title_text conf base p);
Wserver.wprint "%d persons and %d families deleted
\n" nb_ind nb_fam;
Util.trailer conf;
}
;
value print_kill_ancestors conf base =
match p_getenv conf.base_env "can_kill_ancestors" with
[ Some "yes" ->
match find_person_in_env conf base "" with
[ Some p ->
let key = (sou base p.first_name, sou base p.surname, p.occ) in
let _ = Util.base_path [] (conf.bname ^ ".lck") in
let nb_ind = ref 0 in
let nb_fam = ref 0 in
do {
kill_ancestors conf base False p nb_ind nb_fam;
Util.commit_patches conf base;
History.record conf base key "ka";
print_killed conf base p nb_ind.val nb_fam.val;
}
| None -> incorrect_request conf ]
| _ -> incorrect_request conf ]
;