<?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(5, 5, 5, true);
        $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(0, count($possible) - 1);
            $selected[] = array_splice($possible, $index, 1, null)[0];
        }

        return $selected;
    }

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

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

    private function generateCardHeader(){
        $this->SetFont('Times', 'B', 30);
        $this->SetTextColor(0xFF, 0xFF, 0xFF);
        $this->SetFillColor(0x00, 0x00, 0x80);

        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(0x00, 0x00, 0x00);
        $this->SetFillColor(0xFF, 0xFF, 0xFF);

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

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

        $this->Cell($w, $h, $text, 1, 0, 'C', true);
    }

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

        $this->SetFillColor(0xD0, 0xD0, 0xD0);
        $this->SetFont('Times', 'B', 16);
        $this->Cell($w, $h, 'Free!', 1, 0, 'C', true);
        $this->SetFillColor(0xFF, 0xFF, 0xFF);
        $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) / 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($howMany, 1);

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

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