<?php

//Makes use of the tecnickcom/tcpdf library for PDF generation.
require '../../vendor/autoload.php';

class 
BingoPdf extends TCPDF {
    const 
MAX_RETRY 25;

    private 
$wordList;
    private 
$howMany;
    private 
$freeSpace;
    private 
$cardSpacing 10;
    private 
$cardKeys = [];

    public function 
__construct($wordList$howMany$freeSpace true){
        
parent::__construct('P''mm');
        
$this->SetMargins(555true);
        
$this->SetAutoPageBreak(false);
        
$this->wordList $wordList;
        
$this->howMany $howMany;
        
$this->freeSpace $freeSpace;
    }

    public function 
header(){
    }

    public function 
footer(){
    }

    public function 
Output($name 'doc.pdf'$dest 'I'){
        
$this->generate();

        return 
parent::Output($name$dest);
    }

    private function 
generate(){
        
$this->seedGenerator();
        for (
$i 0$i $this->howMany$i++){
            if ((
$i 1) == 0){
                
$this->AddPage();
            }

            
$words $this->generateUniqueCardWords();
            
$this->generateCard($words);
        }
    }

    private function 
seedGenerator(){
        
$seed unpack('Nseed'random_bytes(4));
        
mt_srand($seed['seed']);
    }

    private function 
generateUniqueCardWords(){
        
$retry 0;

        do {
            
$words $this->generateCardWordList($this->wordList);
            
$key md5(implode(';'$words));
        } while (!
in_array($key$this->cardKeys) && $retry++ < self::MAX_RETRY);

        
$this->cardKeys[] = $key;

        return 
$words;
    }

    private function 
generateCardWordList($possible){
        
$selected = [];

        while (
count($selected) < 25){
            
$index mt_rand(0count($possible) - 1);
            
$selected[] = array_splice($possible$index1null)[0];
        }

        return 
$selected;
    }

    private function 
generateCard($words){
        
$this->generateCardHeader();

        foreach (
array_chunk($words5) as $num => $row){
            
$this->generateCardRow($row$num);
        }
        
$this->Ln($this->cardSpacing);
    }

    private function 
generateCardHeader(){
        
$this->SetFont('Times''B'30);
        
$this->SetTextColor(0xFF0xFF0xFF);
        
$this->SetFillColor(0x000x000x80);

        foreach ([
'B''I''N''G''O'] as $letter){
            
$this->DrawCell($letter);
        }
        
$this->Ln();
    }

    private function 
generateCardRow($words$rowNumber){
        
$this->SetFont('Times''R'12);
        
$this->SetTextColor(0x000x000x00);
        
$this->SetFillColor(0xFF0xFF0xFF);

        foreach (
$words as $columnNumber => $word){
            if (
$rowNumber == && $columnNumber == && $this->freeSpace){
                
$this->DrawFreeSpace();
            } else {
                
$this->DrawCell($word);
            }
        }
        
$this->Ln();
    }

    private function 
DrawCell($text){
        list(
$w$h) = $this->getCellSize();

        
$this->Cell($w$h$text10'C'true);
    }

    private function 
DrawFreeSpace(){
        list(
$w$h) = $this->getCellSize();

        
$this->SetFillColor(0xD00xD00xD0);
        
$this->SetFont('Times''B'16);
        
$this->Cell($w$h'Free!'10'C'true);
        
$this->SetFillColor(0xFF0xFF0xFF);
        
$this->SetFont('Times''R'12);
    }

    private function 
getCellSize(){
        
$pageDim $this->getPageDimensions();

        
$pageWidth $pageDim['wk'] - $pageDim['lm'] - $pageDim['rm'];
        
$pageHeight $pageDim['hk'] - $pageDim['tm'] - $pageDim['bm'];

        
$w = ($pageWidth) / 5;
        
$h = ($pageHeight $this->cardSpacing 2) / 6;

        return [
$w$h];
    }
}


$words = isset($_POST['words'])?$_POST['words']:'';
$words explode("\r\n"$words);
$words array_filter($words, function ($v){
    return 
$v !== '';
});
$words array_unique($words);

if (
count($words) < 24){
    echo 
"Request must include at least 25 unique words.";
    exit;
}

$howMany = isset($_POST['howMany'])?(int)$_POST['howMany']:0;
$howMany max($howMany1);

$freeSpace = isset($_POST['freeSpace']) && $_POST['freeSpace'] == 'y';

$pdf = new BingoPdf($words$howMany$freeSpace);
$pdf->Output('BingoCards.pdf''I');