xref: /webtrees/app/Module/FamilyBookChartModule.php (revision 9867b2f0bfec6864e75b2501f3e96895ff42db48)
1168ff6f3Sric2016<?php
2168ff6f3Sric2016/**
3168ff6f3Sric2016 * webtrees: online genealogy
48fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team
5168ff6f3Sric2016 * This program is free software: you can redistribute it and/or modify
6168ff6f3Sric2016 * it under the terms of the GNU General Public License as published by
7168ff6f3Sric2016 * the Free Software Foundation, either version 3 of the License, or
8168ff6f3Sric2016 * (at your option) any later version.
9168ff6f3Sric2016 * This program is distributed in the hope that it will be useful,
10168ff6f3Sric2016 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11168ff6f3Sric2016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12168ff6f3Sric2016 * GNU General Public License for more details.
13168ff6f3Sric2016 * You should have received a copy of the GNU General Public License
14168ff6f3Sric2016 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15168ff6f3Sric2016 */
16e7f56f2aSGreg Roachdeclare(strict_types=1);
17e7f56f2aSGreg Roach
18168ff6f3Sric2016namespace Fisharebest\Webtrees\Module;
19168ff6f3Sric2016
20389266c0SGreg Roachuse Fisharebest\Webtrees\Auth;
21389266c0SGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsPrint;
22168ff6f3Sric2016use Fisharebest\Webtrees\I18N;
23168ff6f3Sric2016use Fisharebest\Webtrees\Individual;
24e46b0479SScrutinizer Auto-Fixeruse Fisharebest\Webtrees\Menu;
25389266c0SGreg Roachuse Fisharebest\Webtrees\Theme;
26389266c0SGreg Roachuse Fisharebest\Webtrees\Tree;
27*9867b2f0SGreg Roachuse Fisharebest\Webtrees\User;
28389266c0SGreg Roachuse stdClass;
29389266c0SGreg Roachuse Symfony\Component\HttpFoundation\Request;
30389266c0SGreg Roachuse Symfony\Component\HttpFoundation\Response;
31168ff6f3Sric2016
32168ff6f3Sric2016/**
33168ff6f3Sric2016 * Class FamilyBookChartModule
34168ff6f3Sric2016 */
3537eb8894SGreg Roachclass FamilyBookChartModule extends AbstractModule implements ModuleChartInterface
36c1010edaSGreg Roach{
3749a243cbSGreg Roach    use ModuleChartTrait;
3849a243cbSGreg Roach
39389266c0SGreg Roach    // Defaults
40389266c0SGreg Roach    private const DEFAULT_GENERATIONS            = '2';
41389266c0SGreg Roach    private const DEFAULT_DESCENDANT_GENERATIONS = '5';
42389266c0SGreg Roach    private const DEFAULT_MAXIMUM_GENERATIONS    = '9';
43389266c0SGreg Roach
44389266c0SGreg Roach    /** @var stdClass */
45389266c0SGreg Roach    private $box;
46389266c0SGreg Roach
47389266c0SGreg Roach    /** @var bool */
48389266c0SGreg Roach    private $show_spouse;
49389266c0SGreg Roach
50389266c0SGreg Roach    /** @var int */
51389266c0SGreg Roach    private $descent;
52389266c0SGreg Roach
53389266c0SGreg Roach    /** @var int */
54389266c0SGreg Roach    private $bhalfheight;
55389266c0SGreg Roach
56389266c0SGreg Roach    /** @var int */
57389266c0SGreg Roach    private $generations;
58389266c0SGreg Roach
59389266c0SGreg Roach    /** @var int */
60389266c0SGreg Roach    private $dgenerations;
61389266c0SGreg Roach
62168ff6f3Sric2016    /**
63168ff6f3Sric2016     * How should this module be labelled on tabs, menus, etc.?
64168ff6f3Sric2016     *
65168ff6f3Sric2016     * @return string
66168ff6f3Sric2016     */
6749a243cbSGreg Roach    public function title(): string
68c1010edaSGreg Roach    {
69bbb76c12SGreg Roach        /* I18N: Name of a module/chart */
70bbb76c12SGreg Roach        return I18N::translate('Family book');
71168ff6f3Sric2016    }
72168ff6f3Sric2016
73168ff6f3Sric2016    /**
74168ff6f3Sric2016     * A sentence describing what this module does.
75168ff6f3Sric2016     *
76168ff6f3Sric2016     * @return string
77168ff6f3Sric2016     */
7849a243cbSGreg Roach    public function description(): string
79c1010edaSGreg Roach    {
80bbb76c12SGreg Roach        /* I18N: Description of the “FamilyBookChart” module */
81bbb76c12SGreg Roach        return I18N::translate('A chart of an individual’s ancestors and descendants, as a family book.');
82168ff6f3Sric2016    }
83168ff6f3Sric2016
84168ff6f3Sric2016    /**
85377a2979SGreg Roach     * CSS class for the URL.
86377a2979SGreg Roach     *
87377a2979SGreg Roach     * @return string
88377a2979SGreg Roach     */
89377a2979SGreg Roach    public function chartMenuClass(): string
90377a2979SGreg Roach    {
91377a2979SGreg Roach        return 'menu-chart-familybook';
92377a2979SGreg Roach    }
93377a2979SGreg Roach
94377a2979SGreg Roach    /**
954eb71cfaSGreg Roach     * Return a menu item for this chart - for use in individual boxes.
964eb71cfaSGreg Roach     *
9760bc3e3fSGreg Roach     * @param Individual $individual
9860bc3e3fSGreg Roach     *
994eb71cfaSGreg Roach     * @return Menu|null
1004eb71cfaSGreg Roach     */
101377a2979SGreg Roach    public function chartBoxMenu(Individual $individual): ?Menu
102c1010edaSGreg Roach    {
103e6562982SGreg Roach        return $this->chartMenu($individual);
104e6562982SGreg Roach    }
105e6562982SGreg Roach
106e6562982SGreg Roach    /**
107e6562982SGreg Roach     * The title for a specific instance of this chart.
108e6562982SGreg Roach     *
109e6562982SGreg Roach     * @param Individual $individual
110e6562982SGreg Roach     *
111e6562982SGreg Roach     * @return string
112e6562982SGreg Roach     */
113e6562982SGreg Roach    public function chartTitle(Individual $individual): string
114e6562982SGreg Roach    {
115e6562982SGreg Roach        /* I18N: %s is an individual’s name */
116e6562982SGreg Roach        return I18N::translate('Family book of %s', $individual->getFullName());
117e6562982SGreg Roach    }
118e6562982SGreg Roach
119e6562982SGreg Roach    /**
120389266c0SGreg Roach     * A form to request the chart parameters.
121389266c0SGreg Roach     *
122389266c0SGreg Roach     * @param Request $request
123389266c0SGreg Roach     * @param Tree    $tree
124*9867b2f0SGreg Roach     * @param User    $user
125389266c0SGreg Roach     *
126389266c0SGreg Roach     * @return Response
127389266c0SGreg Roach     */
128*9867b2f0SGreg Roach    public function getChartAction(Request $request, Tree $tree, User $user): Response
129389266c0SGreg Roach    {
1309b5537c3SGreg Roach        $ajax       = (bool) $request->get('ajax');
131389266c0SGreg Roach        $xref       = $request->get('xref', '');
132389266c0SGreg Roach        $individual = Individual::getInstance($xref, $tree);
133389266c0SGreg Roach
134389266c0SGreg Roach        Auth::checkIndividualAccess($individual);
135*9867b2f0SGreg Roach        Auth::checkComponentAccess($this, 'chart', $tree, $user);
136389266c0SGreg Roach
137389266c0SGreg Roach        $minimum_generations = 2;
138389266c0SGreg Roach        $maximum_generations = (int) $tree->getPreference('MAX_DESCENDANCY_GENERATIONS', self::DEFAULT_MAXIMUM_GENERATIONS);
139389266c0SGreg Roach        $default_generations = (int) $tree->getPreference('DEFAULT_PEDIGREE_GENERATIONS', self::DEFAULT_GENERATIONS);
140389266c0SGreg Roach
141389266c0SGreg Roach        $show_spouse = (bool) $request->get('show_spouse');
142389266c0SGreg Roach        $generations = (int) $request->get('generations', $default_generations);
143389266c0SGreg Roach        $generations = min($generations, $maximum_generations);
144389266c0SGreg Roach        $generations = max($generations, $minimum_generations);
145389266c0SGreg Roach
146389266c0SGreg Roach        // Generations of ancestors/descendants in each mini-tree.
147389266c0SGreg Roach        $book_size = (int) $request->get('book_size', 2);
148389266c0SGreg Roach        $book_size = min($book_size, 5);
149389266c0SGreg Roach        $book_size = max($book_size, 2);
150389266c0SGreg Roach
1519b5537c3SGreg Roach        if ($ajax) {
152389266c0SGreg Roach            return $this->chart($individual, $generations, $book_size, $show_spouse);
153389266c0SGreg Roach        }
154389266c0SGreg Roach
155389266c0SGreg Roach        $ajax_url = $this->chartUrl($individual, [
1569b5537c3SGreg Roach            'ajax'        => true,
157389266c0SGreg Roach            'book_size'   => $book_size,
158389266c0SGreg Roach            'generations' => $generations,
159389266c0SGreg Roach            'show_spouse' => $show_spouse
160389266c0SGreg Roach        ]);
161389266c0SGreg Roach
1629b5537c3SGreg Roach        return $this->viewResponse('modules/family-book-chart/page', [
163389266c0SGreg Roach            'ajax_url'            => $ajax_url,
164389266c0SGreg Roach            'book_size'           => $book_size,
165389266c0SGreg Roach            'generations'         => $generations,
166389266c0SGreg Roach            'individual'          => $individual,
167389266c0SGreg Roach            'maximum_generations' => $maximum_generations,
168389266c0SGreg Roach            'minimum_generations' => $minimum_generations,
16926684e68SGreg Roach            'module_name'         => $this->name(),
170389266c0SGreg Roach            'show_spouse'         => $show_spouse,
171389266c0SGreg Roach            'title'               => $this->chartTitle($individual),
172389266c0SGreg Roach        ]);
173389266c0SGreg Roach    }
174389266c0SGreg Roach
175389266c0SGreg Roach    /**
176389266c0SGreg Roach     * @param Individual $individual
177389266c0SGreg Roach     * @param int        $generations
178389266c0SGreg Roach     * @param int        $book_size
179389266c0SGreg Roach     * @param bool       $show_spouse
180389266c0SGreg Roach     *
181389266c0SGreg Roach     * @return Response
182389266c0SGreg Roach     */
183389266c0SGreg Roach    public function chart(Individual $individual, int $generations, int $book_size, bool $show_spouse): Response
184389266c0SGreg Roach    {
185389266c0SGreg Roach        $this->box = (object) [
186389266c0SGreg Roach            'width'  => Theme::theme()->parameter('chart-box-x'),
187389266c0SGreg Roach            'height' => Theme::theme()->parameter('chart-box-y'),
188389266c0SGreg Roach        ];
189389266c0SGreg Roach
190389266c0SGreg Roach        $this->show_spouse = $show_spouse;
191389266c0SGreg Roach        $this->descent     = $generations;
192389266c0SGreg Roach        $this->generations = $book_size;
193389266c0SGreg Roach
194389266c0SGreg Roach        $this->bhalfheight  = $this->box->height / 2;
195389266c0SGreg Roach        $this->dgenerations = $this->maxDescendencyGenerations($individual, 0);
196389266c0SGreg Roach
197389266c0SGreg Roach        if ($this->dgenerations < 1) {
198389266c0SGreg Roach            $this->dgenerations = 1;
199389266c0SGreg Roach        }
200389266c0SGreg Roach
201389266c0SGreg Roach        // @TODO - this is just a wrapper around the old code.
202389266c0SGreg Roach        ob_start();
203389266c0SGreg Roach        $this->printFamilyBook($individual, $generations);
204389266c0SGreg Roach        $html = ob_get_clean();
205389266c0SGreg Roach
206389266c0SGreg Roach        return new Response($html);
207389266c0SGreg Roach    }
208389266c0SGreg Roach
209389266c0SGreg Roach    /**
210389266c0SGreg Roach     * Prints descendency of passed in person
211389266c0SGreg Roach     *
212389266c0SGreg Roach     * @param int             $generation
213389266c0SGreg Roach     * @param Individual|null $person
214389266c0SGreg Roach     *
215389266c0SGreg Roach     * @return float
216389266c0SGreg Roach     */
217389266c0SGreg Roach    private function printDescendency($generation, Individual $person = null): float
218389266c0SGreg Roach    {
219389266c0SGreg Roach        if ($generation > $this->dgenerations) {
220389266c0SGreg Roach            return 0;
221389266c0SGreg Roach        }
222389266c0SGreg Roach
223389266c0SGreg Roach        echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>';
224389266c0SGreg Roach        $numkids = 0.0;
225389266c0SGreg Roach
226389266c0SGreg Roach        // Load children
227389266c0SGreg Roach        $children = [];
228389266c0SGreg Roach        if ($person instanceof Individual) {
229389266c0SGreg Roach            // Count is position from center to left, dgenerations is number of generations
230389266c0SGreg Roach            if ($generation < $this->dgenerations) {
231389266c0SGreg Roach                // All children, from all partners
232389266c0SGreg Roach                foreach ($person->getSpouseFamilies() as $family) {
233389266c0SGreg Roach                    foreach ($family->getChildren() as $child) {
234389266c0SGreg Roach                        $children[] = $child;
235389266c0SGreg Roach                    }
236389266c0SGreg Roach                }
237389266c0SGreg Roach            }
238389266c0SGreg Roach        }
239389266c0SGreg Roach        if ($generation < $this->dgenerations) {
240389266c0SGreg Roach            if (!empty($children)) {
241389266c0SGreg Roach                // real people
242389266c0SGreg Roach                echo '<table cellspacing="0" cellpadding="0" border="0" >';
243389266c0SGreg Roach                foreach ($children as $i => $child) {
244389266c0SGreg Roach                    echo '<tr><td>';
245389266c0SGreg Roach                    $kids = $this->printDescendency($generation + 1, $child);
246389266c0SGreg Roach                    $numkids += $kids;
247389266c0SGreg Roach                    echo '</td>';
248389266c0SGreg Roach                    // Print the lines
249389266c0SGreg Roach                    if (count($children) > 1) {
250389266c0SGreg Roach                        if ($i === 0) {
251389266c0SGreg Roach                            // Adjust for the first column on left
252389266c0SGreg Roach                            $h = round(((($this->box->height) * $kids) + 8) / 2); // Assumes border = 1 and padding = 3
253389266c0SGreg Roach                            //  Adjust for other vertical columns
254389266c0SGreg Roach                            if ($kids > 1) {
255389266c0SGreg Roach                                $h = ($kids - 1) * 4 + $h;
256389266c0SGreg Roach                            }
257389266c0SGreg Roach                            echo '<td class="align-bottom">',
258389266c0SGreg Roach                            '<img id="vline_', $child->xref(), '" src="', Theme::theme()->parameter('image-vline'), '" width="3" height="', $h - 4, '"></td>';
259389266c0SGreg Roach                        } elseif ($i === count($children) - 1) {
260389266c0SGreg Roach                            // Adjust for the first column on left
261389266c0SGreg Roach                            $h = round(((($this->box->height) * $kids) + 8) / 2);
262389266c0SGreg Roach                            // Adjust for other vertical columns
263389266c0SGreg Roach                            if ($kids > 1) {
264389266c0SGreg Roach                                $h = ($kids - 1) * 4 + $h;
265389266c0SGreg Roach                            }
266389266c0SGreg Roach                            echo '<td class="align-top">',
267389266c0SGreg Roach                            '<img class="bvertline" width="3" id="vline_', $child->xref(), '" src="', Theme::theme()->parameter('image-vline'), '" height="', $h - 2, '"></td>';
268389266c0SGreg Roach                        } else {
269389266c0SGreg Roach                            echo '<td class="align-bottomm"style="background: url(', Theme::theme()->parameter('image-vline'), ');">',
270389266c0SGreg Roach                            '<img class="spacer"  width="3" src="', Theme::theme()->parameter('image-spacer'), '"></td>';
271389266c0SGreg Roach                        }
272389266c0SGreg Roach                    }
273389266c0SGreg Roach                    echo '</tr>';
274389266c0SGreg Roach                }
275389266c0SGreg Roach                echo '</table>';
276389266c0SGreg Roach            } else {
277389266c0SGreg Roach                // Hidden/empty boxes - to preserve the layout
278389266c0SGreg Roach                echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>';
279389266c0SGreg Roach                $numkids += $this->printDescendency($generation + 1, null);
280389266c0SGreg Roach                echo '</td></tr></table>';
281389266c0SGreg Roach            }
282389266c0SGreg Roach            echo '</td>';
283389266c0SGreg Roach            echo '<td>';
284389266c0SGreg Roach        }
285389266c0SGreg Roach
286389266c0SGreg Roach        if ($numkids === 0.0) {
287389266c0SGreg Roach            $numkids = 1;
288389266c0SGreg Roach        }
289389266c0SGreg Roach        echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>';
290389266c0SGreg Roach        if ($person instanceof Individual) {
291389266c0SGreg Roach            echo FunctionsPrint::printPedigreePerson($person);
292389266c0SGreg Roach            echo '</td><td>',
293389266c0SGreg Roach            '<img class="linef1" src="', Theme::theme()->parameter('image-hline'), '" width="8" height="3">';
294389266c0SGreg Roach        } else {
295389266c0SGreg Roach            echo '<div style="width:', $this->box->width + 19, 'px; height:', $this->box->height + 8, 'px;"></div>',
296389266c0SGreg Roach            '</td><td>';
297389266c0SGreg Roach        }
298389266c0SGreg Roach
299389266c0SGreg Roach        // Print the spouse
300389266c0SGreg Roach        if ($generation === 1 && $person instanceof Individual) {
301389266c0SGreg Roach            if ($this->show_spouse) {
302389266c0SGreg Roach                foreach ($person->getSpouseFamilies() as $family) {
303389266c0SGreg Roach                    $spouse = $family->getSpouse($person);
304389266c0SGreg Roach                    echo '</td></tr><tr><td>';
305389266c0SGreg Roach                    echo FunctionsPrint::printPedigreePerson($spouse);
306389266c0SGreg Roach                    $numkids += 0.95;
307389266c0SGreg Roach                    echo '</td><td>';
308389266c0SGreg Roach                }
309389266c0SGreg Roach            }
310389266c0SGreg Roach        }
311389266c0SGreg Roach        echo '</td></tr></table>';
312389266c0SGreg Roach        echo '</td></tr>';
313389266c0SGreg Roach        echo '</table>';
314389266c0SGreg Roach
315389266c0SGreg Roach        return $numkids;
316389266c0SGreg Roach    }
317389266c0SGreg Roach
318389266c0SGreg Roach    /**
319389266c0SGreg Roach     * Prints pedigree of the person passed in
320389266c0SGreg Roach     *
321389266c0SGreg Roach     * @param Individual $person
322389266c0SGreg Roach     * @param int        $count
323389266c0SGreg Roach     *
324389266c0SGreg Roach     * @return void
325389266c0SGreg Roach     */
326389266c0SGreg Roach    private function printPersonPedigree($person, $count)
327389266c0SGreg Roach    {
328389266c0SGreg Roach        if ($count >= $this->generations) {
329389266c0SGreg Roach            return;
330389266c0SGreg Roach        }
331389266c0SGreg Roach
332389266c0SGreg Roach        $genoffset = $this->generations; // handle pedigree n generations lines
333389266c0SGreg Roach        //-- calculate how tall the lines should be
334389266c0SGreg Roach        $lh = ($this->bhalfheight) * (2 ** ($genoffset - $count - 1));
335389266c0SGreg Roach        //
336389266c0SGreg Roach        //Prints empty table columns for children w/o parents up to the max generation
337389266c0SGreg Roach        //This allows vertical line spacing to be consistent
338389266c0SGreg Roach        if (count($person->getChildFamilies()) == 0) {
339389266c0SGreg Roach            echo '<table cellspacing="0" cellpadding="0" border="0" >';
340389266c0SGreg Roach            $this->printEmptyBox();
341389266c0SGreg Roach
342389266c0SGreg Roach            //-- recursively get the father’s family
343389266c0SGreg Roach            $this->printPersonPedigree($person, $count + 1);
344389266c0SGreg Roach            echo '</td><td></tr>';
345389266c0SGreg Roach            $this->printEmptyBox();
346389266c0SGreg Roach
347389266c0SGreg Roach            //-- recursively get the mother’s family
348389266c0SGreg Roach            $this->printPersonPedigree($person, $count + 1);
349389266c0SGreg Roach            echo '</td><td></tr></table>';
350389266c0SGreg Roach        }
351389266c0SGreg Roach
352389266c0SGreg Roach        // Empty box section done, now for regular pedigree
353389266c0SGreg Roach        foreach ($person->getChildFamilies() as $family) {
354389266c0SGreg Roach            echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td class="align-bottom">';
355389266c0SGreg Roach            // Determine line height for two or more spouces
356389266c0SGreg Roach            // And then adjust the vertical line for the root person only
357389266c0SGreg Roach            $famcount = 0;
358389266c0SGreg Roach            if ($this->show_spouse) {
359389266c0SGreg Roach                // count number of spouses
360389266c0SGreg Roach                $famcount += count($person->getSpouseFamilies());
361389266c0SGreg Roach            }
362389266c0SGreg Roach            $savlh = $lh; // Save current line height
363389266c0SGreg Roach            if ($count == 1 && $genoffset <= $famcount) {
364389266c0SGreg Roach                $linefactor = 0;
365389266c0SGreg Roach                // genoffset of 2 needs no adjustment
366389266c0SGreg Roach                if ($genoffset > 2) {
367389266c0SGreg Roach                    $tblheight = $this->box->height + 8;
368389266c0SGreg Roach                    if ($genoffset == 3) {
369389266c0SGreg Roach                        if ($famcount == 3) {
370389266c0SGreg Roach                            $linefactor = $tblheight / 2;
371389266c0SGreg Roach                        } elseif ($famcount > 3) {
372389266c0SGreg Roach                            $linefactor = $tblheight;
373389266c0SGreg Roach                        }
374389266c0SGreg Roach                    }
375389266c0SGreg Roach                    if ($genoffset == 4) {
376389266c0SGreg Roach                        if ($famcount == 4) {
377389266c0SGreg Roach                            $linefactor = $tblheight;
378389266c0SGreg Roach                        } elseif ($famcount > 4) {
379389266c0SGreg Roach                            $linefactor = ($famcount - $genoffset) * ($tblheight * 1.5);
380389266c0SGreg Roach                        }
381389266c0SGreg Roach                    }
382389266c0SGreg Roach                    if ($genoffset == 5) {
383389266c0SGreg Roach                        if ($famcount == 5) {
384389266c0SGreg Roach                            $linefactor = 0;
385389266c0SGreg Roach                        } elseif ($famcount > 5) {
386389266c0SGreg Roach                            $linefactor = $tblheight * ($famcount - $genoffset);
387389266c0SGreg Roach                        }
388389266c0SGreg Roach                    }
389389266c0SGreg Roach                }
390389266c0SGreg Roach                $lh = (($famcount - 1) * ($this->box->height) - ($linefactor));
391389266c0SGreg Roach                if ($genoffset > 5) {
392389266c0SGreg Roach                    $lh = $savlh;
393389266c0SGreg Roach                }
394389266c0SGreg Roach            }
395389266c0SGreg Roach            echo '<img class="line3 pvline"  src="', Theme::theme()->parameter('image-vline'), '" width="3" height="', $lh, '"></td>',
396389266c0SGreg Roach            '<td>',
397389266c0SGreg Roach            '<img class="linef2" src="', Theme::theme()->parameter('image-hline'), '" height="3"></td>',
398389266c0SGreg Roach            '<td>';
399389266c0SGreg Roach            $lh = $savlh; // restore original line height
400389266c0SGreg Roach            //-- print the father box
401389266c0SGreg Roach            echo FunctionsPrint::printPedigreePerson($family->getHusband());
402389266c0SGreg Roach            echo '</td>';
403389266c0SGreg Roach            if ($family->getHusband()) {
404389266c0SGreg Roach                echo '<td>';
405389266c0SGreg Roach                //-- recursively get the father’s family
406389266c0SGreg Roach                $this->printPersonPedigree($family->getHusband(), $count + 1);
407389266c0SGreg Roach                echo '</td>';
408389266c0SGreg Roach            } else {
409389266c0SGreg Roach                echo '<td>';
410389266c0SGreg Roach                if ($genoffset > $count) {
411389266c0SGreg Roach                    echo '<table cellspacing="0" cellpadding="0" border="0" >';
412389266c0SGreg Roach                    for ($i = 1; $i < (pow(2, ($genoffset) - $count) / 2); $i++) {
413389266c0SGreg Roach                        $this->printEmptyBox();
414389266c0SGreg Roach                        echo '</tr>';
415389266c0SGreg Roach                    }
416389266c0SGreg Roach                    echo '</table>';
417389266c0SGreg Roach                }
418389266c0SGreg Roach            }
419389266c0SGreg Roach            echo '</tr><tr>',
420389266c0SGreg Roach            '<td class="align-top"><img class="pvline" alt="" role="presentation" src="', Theme::theme()->parameter('image-vline'), '" width="3" height="', $lh, '"></td>',
421389266c0SGreg Roach            '<td><img class="linef3" alt="" role="presentation" src="', Theme::theme()->parameter('image-hline'), '" height="3"></td>',
422389266c0SGreg Roach            '<td>';
423389266c0SGreg Roach            //-- print the mother box
424389266c0SGreg Roach            echo FunctionsPrint::printPedigreePerson($family->getWife());
425389266c0SGreg Roach            echo '</td>';
426389266c0SGreg Roach            if ($family->getWife()) {
427389266c0SGreg Roach                echo '<td>';
428389266c0SGreg Roach                //-- recursively print the mother’s family
429389266c0SGreg Roach                $this->printPersonPedigree($family->getWife(), $count + 1);
430389266c0SGreg Roach                echo '</td>';
431389266c0SGreg Roach            } else {
432389266c0SGreg Roach                echo '<td>';
433389266c0SGreg Roach                if ($count < $genoffset - 1) {
434389266c0SGreg Roach                    echo '<table cellspacing="0" cellpadding="0" border="0" >';
435389266c0SGreg Roach                    for ($i = 1; $i < (pow(2, ($genoffset - 1) - $count) / 2) + 1; $i++) {
436389266c0SGreg Roach                        $this->printEmptyBox();
437389266c0SGreg Roach                        echo '</tr>';
438389266c0SGreg Roach                        $this->printEmptyBox();
439389266c0SGreg Roach                        echo '</tr>';
440389266c0SGreg Roach                    }
441389266c0SGreg Roach                    echo '</table>';
442389266c0SGreg Roach                }
443389266c0SGreg Roach            }
444389266c0SGreg Roach            echo '</tr>',
445389266c0SGreg Roach            '</table>';
446389266c0SGreg Roach            break;
447389266c0SGreg Roach        }
448389266c0SGreg Roach    }
449389266c0SGreg Roach
450389266c0SGreg Roach    /**
451389266c0SGreg Roach     * Calculates number of generations a person has
452e6562982SGreg Roach     *
453e6562982SGreg Roach     * @param Individual $individual
454389266c0SGreg Roach     * @param int        $depth
455e6562982SGreg Roach     *
456389266c0SGreg Roach     * @return int
457e6562982SGreg Roach     */
458389266c0SGreg Roach    private function maxDescendencyGenerations(Individual $individual, $depth): int
459e6562982SGreg Roach    {
460389266c0SGreg Roach        if ($depth > $this->generations) {
461389266c0SGreg Roach            return $depth;
462389266c0SGreg Roach        }
463389266c0SGreg Roach        $maxdc = $depth;
464389266c0SGreg Roach        foreach ($individual->getSpouseFamilies() as $family) {
465389266c0SGreg Roach            foreach ($family->getChildren() as $child) {
466389266c0SGreg Roach                $dc = $this->maxDescendencyGenerations($child, $depth + 1);
467389266c0SGreg Roach                if ($dc >= $this->generations) {
468389266c0SGreg Roach                    return $dc;
469389266c0SGreg Roach                }
470389266c0SGreg Roach                if ($dc > $maxdc) {
471389266c0SGreg Roach                    $maxdc = $dc;
472389266c0SGreg Roach                }
473389266c0SGreg Roach            }
474389266c0SGreg Roach        }
475389266c0SGreg Roach        $maxdc++;
476389266c0SGreg Roach        if ($maxdc == 1) {
477389266c0SGreg Roach            $maxdc++;
478389266c0SGreg Roach        }
479389266c0SGreg Roach
480389266c0SGreg Roach        return $maxdc;
481389266c0SGreg Roach    }
482389266c0SGreg Roach
483389266c0SGreg Roach    /**
484389266c0SGreg Roach     * Print empty box
485389266c0SGreg Roach     *
486389266c0SGreg Roach     * @return void
487389266c0SGreg Roach     */
488389266c0SGreg Roach
489389266c0SGreg Roach    private function printEmptyBox()
490389266c0SGreg Roach    {
491389266c0SGreg Roach        echo Theme::theme()->individualBoxEmpty();
492389266c0SGreg Roach    }
493389266c0SGreg Roach
494389266c0SGreg Roach    /**
495389266c0SGreg Roach     * Print a “Family Book” for an individual
496389266c0SGreg Roach     *
497389266c0SGreg Roach     * @param Individual $person
498389266c0SGreg Roach     * @param int        $descent_steps
499389266c0SGreg Roach     *
500389266c0SGreg Roach     * @return void
501389266c0SGreg Roach     */
502389266c0SGreg Roach    private function printFamilyBook(Individual $person, $descent_steps)
503389266c0SGreg Roach    {
504389266c0SGreg Roach        if ($descent_steps == 0) {
505389266c0SGreg Roach            return;
506389266c0SGreg Roach        }
507389266c0SGreg Roach
508389266c0SGreg Roach        echo
509389266c0SGreg Roach        '<h3>',
510389266c0SGreg Roach            /* I18N: %s is an individual’s name */
511389266c0SGreg Roach        I18N::translate('Family of %s', $person->getFullName()),
512389266c0SGreg Roach        '</h3>',
513389266c0SGreg Roach        '<table cellspacing="0" cellpadding="0" border="0" ><tr><td class="align-middle">';
514389266c0SGreg Roach        $this->dgenerations = $this->generations;
515389266c0SGreg Roach        $this->printDescendency(1, $person);
516389266c0SGreg Roach        echo '</td><td class="align-middle">';
517389266c0SGreg Roach        $this->printPersonPedigree($person, 1);
518389266c0SGreg Roach        echo '</td></tr></table><br><br><hr class="family-break"><br><br>';
519389266c0SGreg Roach        foreach ($person->getSpouseFamilies() as $family) {
520389266c0SGreg Roach            foreach ($family->getChildren() as $child) {
521389266c0SGreg Roach                $this->printFamilyBook($child, $descent_steps - 1);
522389266c0SGreg Roach            }
523389266c0SGreg Roach        }
524e6562982SGreg Roach    }
525168ff6f3Sric2016}
526