output_type = $output_type; } // ================ // Print the Report // ================ public function print() { $report = new PZFacts_Print(); $report->subscription_serial = $_SESSION['subscription_serial']; $report->usersubscription_serial = $_SESSION['usersubscription_serial']; $report->output_type = $this->output_type; ob_clean(); if ($this->output_type == "string") { return $report->render(); } else { $report->render(); } } } // ========================== // Class to Generate the .pdf // ========================== class PZFacts_Print extends TCPDF { // Variables public $subscription_serial = 0; public $usersubscription_serial = 0; public $report_header_title = ""; public $first_page = true; public $output_type = "normal"; // =============== // Debug an Object // =============== public function debug($object = "") { echo "
";
        print_r($object);
        exit();
    }

    // =================
    // Render the Report
    // =================

    public function render() {

        set_time_limit(0);

        $subscription = (new Subscriptions())->getSubscription($this->subscription_serial);

        if ($subscription->count() === 0) {
            $this->logError("Invalid Subscription ({$this->subscription_serial}): " . __METHOD__);
        }

        $userssubscription = (new Users())->getUserSubscription($this->usersubscription_serial);

        $user_subscription_start_date = $userssubscription->record->usersubscription_start_date;
        $user_subscription_end_date   = $userssubscription->record->usersubscription_end_date;

        $planningzoningfacts = (new PlanningAndZoningFacts())->getPZFactsPage($user_subscription_start_date, $user_subscription_end_date);

        // Set report defaults
        $this->report_header_title = $subscription->record->subscription_full_title;
        $this->title = $subscription->record->subscription_full_title;

        $this->SetFont("Calibri");
        $this->SetMargins(2, 26, 10);
        $this->SetHeaderMargin(10);
        $this->SetFooterMargin(10);
        $this->setCellPaddings(0, 0, 0, 0);
        $this->setCellMargins(2, 0, 0, 0);

        $card = function (float $x, float $y, float $w, float $h, array $d) {

            // Card background + border
            $this->SetDrawColor(210, 210, 210);
            $this->SetFillColor(250, 250, 250);
            $this->Rect($x, $y, $w, $h, 'DF');

            // Header bar
            $headerH = 10;
            $this->SetFillColor(30, 93, 168); // Bootstrap-ish primary
            $this->Rect($x, $y, $w, $headerH, 'F');

            // Header text
            $this->SetTextColor(255, 255, 255);
            $this->SetFont('helvetica', 'B', 11);
            $this->SetXY($x + 3, $y + 2.5);
            $this->Cell($w - 6, 0, "Project Name: {$d['pzfact_project_name']}", 0, 0, 'L', false);

            // Body
            $this->SetTextColor(20, 20, 20);
            $this->SetFont('helvetica', '', 9);

            $padX = 3;
            $padY = 3;

            $curY = $y + $headerH + $padY;

            $bodyX = $x + $padX;
            $bodyW = $w - ($padX * 2);

            $colGap = 6;
            $colW = ($bodyW - $colGap) / 2;

            $leftX = $bodyX;
            $rightX = $bodyX + $colW + $colGap;

            $labelW = 38; // tweak to taste

            $row2 = function (string $l1, string $v1, string $l2, string $v2) use (&$curY, $leftX, $rightX, $colW, $labelW) {

                $yStart = $curY;

                // LEFT Cell

                $this->SetXY($leftX, $yStart);
                $this->SetFont('helvetica', 'B', 9);
                $this->Cell($labelW, 0, $l1, 0, 0, 'L');
                $this->Cell(2, 0, '', 0, 0); // spacer
                $this->SetFont('helvetica', '', 9);
                $this->MultiCell($colW - $labelW - 2, 0, $v1, 0, 'L', false, 1);

                $yAfterLeft = $this->GetY();

                // RIGHT Cell (reset to same starting Y)

                $this->SetXY($rightX, $yStart);
                $this->SetFont('helvetica', 'B', 9);
                $this->Cell($labelW, 0, $l2, 0, 0, 'L');
                $this->SetFont('helvetica', '', 9);
                $this->MultiCell($colW - $labelW, 0, $v2, 0, 'L', false, 1);
                $yAfterRight = $this->GetY();

                // Advance cursor to max height used
                $curY = max($yAfterLeft, $yAfterRight) + 1;
            };

            $row1 = function (string $label, string $value) use (&$curY, $leftX, $bodyW, $labelW) {

                $yStart = $curY;

                $this->SetXY($leftX, $yStart);
                $this->SetFont('helvetica', 'B', 9);
                $this->Cell($labelW, 0, $label, 0, 0, 'L');
                $this->Cell(2, 0, '', 0, 0); // spacer

                $this->SetFont('helvetica', '', 9);
                $this->MultiCell($bodyW - $labelW - 10, 0, $value, 0, 'L', false, 1);

                $curY = $this->GetY() + 1;
            };

            $row2('Project Description:', $d['pzfact_project_description'], 'Project Type:',            $d['pzfact_project_type']);
            $row2('Architect/Engineer: ', $d['pzfact_professional_name'],   'Estimated Project Value:', $d['pzfact_dollar_value']);
            $row2('',                     '',                               'District:',                $d['pzfact_district']);
            $row2('Owner Name: ',         $d['pzfact_owner_name'],          'Land Lot:',                $d['pzfact_land_lot']);
            $row2('Owner Address: ',      $d['pzfact_owner_address'],       'Action Code:',             $d['pzfact_action_code']);
            $row2('Owner Phone: ',        $d['pzfact_owner_phone'],         'Action Date:',             $d['pzfact_action_date']);
            $row2('',                     '',                               'Lot Acres:',               $d['pzfact_acres']);
            $row2('',                     '',                               '', '');
            
            $row1('Status:', $d['pzfact_status']);
        };

        // Get the data for the report

        $this->AddPage('L', 'LETTER');

        $marginL = 10;
        $marginT = 20; // below header area
        $pageW   = $this->getPageWidth();
        $pageH   = $this->getPageHeight();

        $usableW = $pageW - ($marginL * 2);
        $usableH = $pageH - $marginT - 12; // leave footer space

        $gapY    = 6;

        // Two rows per page
        $cardW   = $usableW;
        $cardH   = ($usableH - $gapY) / 2;

        $index   = 0;

        foreach ($planningzoningfacts->record as $planningzoningfact) {

            // Add a new page every 2 cards
            if ($index > 0 && $index % 2 === 0) {
                $this->AddPage('L', 'LETTER');
            }

            $slot = $index % 2;

            $x = $marginL;
            $y = $marginT + ($slot * ($cardH + $gapY));

            // Map your XML fields to the card placeholders (use verbose)

            $d = [
                // Left Side of Card
                'subscription_serial' => trim((string) $planningzoningfact->pzfact_legacy_id),
                'pzfact_project_description' => trim((string) $planningzoningfact->pzfact_project_description),
                'pzfact_project_name' => trim((string) $planningzoningfact->pzfact_project_name),
                'pzfact_project_type' => trim((string) $planningzoningfact->pzfact_project_type_verbose),
                'pzfact_professional_name' => trim((string) $planningzoningfact->pzfact_professional_name),
                'pzfact_owner_name' => trim((string) $planningzoningfact->pzfact_owner_name),
                'pzfact_owner_address' => trim((string) $planningzoningfact->pzfact_owner_address),
                'pzfact_owner_phone' => $this->formatPhoneNumber(trim((string) $planningzoningfact->pzfacts_owner_phone)),
                // Right Side of Card
                'pzfact_dollar_value' => trim((string) $planningzoningfact->pzfact_dollar_value),
                'pzfact_district' => trim((string) $planningzoningfact->pzfact_district),
                'pzfact_land_lot' => trim((string) $planningzoningfact->pzfact_land_lot),
                'pzfact_action_code' => trim((string) $planningzoningfact->pzfact_action_code_verbose),
                'pzfact_action_date' => trim((string) $planningzoningfact->pzfact_action_date_verbose),
                'pzfact_acres' => trim((string) $planningzoningfact->pzfact_acres),
                'pzfact_entry_date' => trim((string) $planningzoningfact->pzfact_entry_date_verbose),
                'pzfact_status' => trim((string) $planningzoningfact->pzfact_status),
                'pzfact_dollar_value' => trim((string) $planningzoningfact->pzfact_dollar_value),
            ];

            $card($x, $y, $cardW, $cardH, $d);

            $index++;
        }


        // -----------------
        // Render the Report
        // -----------------

        $this->SetFont('helvetica', '', 9);

        // --------------
        // Return the pdf
        // --------------

        if ($this->output_type == "string") {
            return $this->Output("{$subscription->record->subscription_full_title}.pdf", "S");
        } else {
            $this->Output("{$subscription->record->subscription_full_title}.pdf");
        }
    }

    // ======
    // Header
    // ======

    public function Header() {

        $this->setCellPaddings(0, 0, 0, 0);
        $this->setCellMargins(2, 0, 0, 0);

        $this->Image("images/dec-international-logo.png", 250, 8, 20, 8);

        $this->SetFont("Calibri", "B", 16);

        $this->Cell(4, 0, "", 0, 0, "L");
        $this->Cell(0, 0, $this->report_header_title . " Report", 0, 0, "L");

        $this->Ln(10);
    }

    // ======
    // Footer
    // ======

    public function Footer() {



        $this->SetFont("Calibri ", "I", 8);

        $X = $this->GetX();

        $this->Cell(0, 10, "DEC International   ", 0, false, "C");

        $this->SetX($X);

        $this->Cell(40, 10, "Page " . $this->getAliasNumPage() . "/" . $this->getAliasNbPages(), 0, false, "L");
        $this->Cell(0, 10, date("n/j/Y g:i A   "), 0, false, "R"
        );
    }

    // =======================
    // Stripe the printed line
    // =======================

    private function stripeLine($pRowCount = 0, $pRowWidth = 0) {

        $this->SetFillColor(($pRowCount % 2) ? 220 : 255);
        $X = $this->GetX();
        $this->Cell($pRowWidth, 0, "", 0, 0, "L", true);
        $this->SetX($X);
    }

    // =======================
    // Format Raw Phone Number
    // =======================

    public function formatPhoneNumber(string $phonenumber): string {

        // Remove everything except digits
        $digits = preg_replace('/\D+/', '', $phonenumber);

        // Handle leading country code (US)
        if (strlen($digits) === 11 && str_starts_with($digits, '1')) {
            $digits = substr($digits, 1);
        }

//        // Must be exactly 10 digits to format
//        if (strlen($digits) !== 10) {
//            return $phonenumber; // return original if invalid
//        }

        return substr($digits, 0, 3) . '-' .
                substr($digits, 3, 3) . '-' .
                substr($digits, 6, 4);
    }
}

?>