<?php
/**
 * This file provides the correspondence class
 *
 * @author Camil Staps
 *
 * BusinessAdmin: administrative software for small companies
 * Copyright (C) 2015 Camil Staps (ViviSoft)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * An extension of FPDF to generate personalized correspondence PDFs
 */
class Correspondence extends FPDF {
	/**
	 * @var $contact                Holds the contact this correspondence will be sent to
	 * @var $language               Holds the language this correspondence should be sent in
	 */
	var $contact, $language;

	/**
	 * If you'd want, you could change these constants to encode an RGB colour for headings in your PDFs
	 */
	const HEAD_RED = 0;
	const HEAD_GREEN = 0;
	const HEAD_BLUE = 0;

	/**
	 * Available languages
	 *
	 * @see _()                     Translation function
	 * @see $translations           Translations table
	 */
	const LANGUAGES = ['en', 'nl'];

	/**
	 * Array holding the translations
	 *
	 * @see _()                     A function to translate
	 */
	protected static $translations = [
		'adres' => [
			'en' => 'Address',
			'nl' => 'Adres'],
		'amount' => [
			'en' => 'Amount',
			'nl' => 'Subtotaal'],
		'amount-due' => [
			'en' => 'Total amount due',
			'nl' => 'Te voldoen'],
		'biccode' => [
			'en' => 'The BIC code of our bank is %%.',
			'nl' => 'De BIC-code van de bank is %%.'],
		'btwnr' => [
			'en' => 'VAT nr',
			'nl' => 'BTW nr'],
		'description' => [
			'en' => 'Description',
			'nl' => 'Omschrijving'],
		'due-date' => [
			'en' => 'Due date',
			'nl' => 'Vervaldatum'],
		'email' => [
			'en' => 'Email',
			'nl' => 'Email'],
		'iban' => [
			'en' => 'IBAN',
			'nl' => 'IBAN'],
		'invoice' => [
			'en' => 'Invoice',
			'nl' => 'Factuur'],
		'invoice-date' => [
			'en' => 'Invoice date',
			'nl' => 'Factuurdatum'],
		'invoice-nr' => [
			'en' => 'Invoice number',
			'nl' => 'Factuurnummer'],
		'price-excl' => [
			'en' => 'Price excl.',
			'nl' => 'Prijs excl.'],
		'price-incl' => [
			'en' => 'Price incl.',
			'nl' => 'Prijs incl.'],
		'request' =>  [
			'en' => 'You are kindly requested to transfer the total amount before the due date to the provided IBAN nr.',
			'nl' => 'U wordt vriendelijk verzocht het te voldoen bedrag voor de vervaldatum van de factuur over te maken naar opgegeven IBAN-nummer.'],
		'tel-nr' => [
			'en' => 'Tel.',
			'nl' => 'Tel.'],
		'total' => [
			'en' => 'Total',
			'nl' => 'Totaal'],
		'vat' => [
			'en' => 'VAT',
			'nl' => 'BTW'],
		'mail-offer' => [
			'en' => "Dear {{getContact-name}},\r\n\r\nPlease find attached your invoice. You can either pay by bank transfer, as indicated on the invoice, or using Paypal or a credit card on {{getPaymentUrl}}.\r\n\r\nThank you in advance,\r\n\r\n{{{invoice_name}}}",
			'nl' => "Beste {{getContact-name}},\r\n\r\nBijgevoegd vindt u uw factuur. U kunt per bankoverschrijving betalen, zoals aangegeven op de factuur, of met Paypal of een credit card op {{getPaymentUrl}}.\r\n\r\nAlvast hartelijk dank,\r\n\r\n{{{invoice_name}}}"],
		'mail-offer-paid' => [
			'en' => "Dear {{getOffer-getContact-name}},\r\n\r\nYour invoice at {{getOffer-getPaymentUrl}} has been paid.\r\n\r\nThank you,\r\n\r\n{{{invoice_name}}}",
			'nl' => "Beste {{getOffer-getContact-name}},\r\n\r\nUw factuur op {{getOffer-getPaymentUrl}} is betaald.\r\n\r\nHartelijk dank,\r\n\r\n{{{invoice_name}}}"],
	];

	/** @var $page_height           The height of a page in millimeters */
	protected static $page_height   = 297; // A4
	/** @var $margin_bottom         The bottom margin in millimeters */
	protected static $margin_bottom = 30;

	/**
	 * Translate a string
	 *
	 * @see $translations           The array holding the translations
	 *
	 * @param string $key           The string to translate
	 *
	 * @return string               The translated string
	 */
	public function _($key) {
		if (!array_key_exists($key, self::$translations))
			return $key;
		return self::$translations[$key][$this->language];
	}

	/**
	 * Translate a string, statically
	 *
	 * @param string $key           The string to translate
	 * @param string $lang          The language to translate to (two-letter code)
	 *
	 * @return string               The translated string
	 */
	public static function __($key, $lang) {
		if (!array_key_exists($key, self::$translations))
			return $key;
		if (!array_key_exists($lang, self::$translations[$key]))
			return $key;
		return self::$translations[$key][$lang];
	}

	/**
	 * Translate a string, statically, and resolve (@see resolve) it
	 *
	 * @param string $key           The string to translate
	 * @param string $lang          The language to translate to (two-letter code)
	 * @param mixed $obj            The object to resolve
	 *
	 * @return string               The resolved translated string
	 */
	public static function __r($key, $lang, $obj) {
		return self::resolve(self::__($key, $lang), $obj);
	}

	/**
	 * Resolve a string
	 *
	 * Resolves {{keyA-keyB-keyC}} to e.g. $obj->keyA()->keyB->keyC(), where
	 * first the function (e.g. keyA()) is tried, and then the property (e.g.
	 * keyB).
	 *
	 * Resolves {{{const}}} to Constants::const.
	 *
	 * @param string $string        The string to resolve
	 * @param mixed $obj            The object to use
	 *
	 * @return string               The generated string
	 */
	public static function resolve($string, $obj) {
		$string = preg_replace_callback('/\{\{\{(\w+)\}\}\}/', function ($matches) {
			$key = $matches[1];
			return constant("Constants::$key");
		}, $string);
		$string = preg_replace_callback('/\{\{([\w-]+)\}\}/', function ($matches) use ($obj) {
			$keys = explode('-', $matches[1]);
			$temp = $obj;
			foreach ($keys as $key) {
				if (method_exists($temp, $key)) {
					$temp = call_user_func([$temp, $key]);
				} else {
					$temp = $temp->$key;
				}
			}
			return $temp;
		}, $string);
		return $string;
	}

	/**
	 * Create a new PDF
	 *
	 * @param string $orientation   See the FPDF class specs
	 * @param string $unit          See the FPDF class specs
	 * @param string $size          See the FPDF class specs
	 */
	function __construct() {
		$this->FPDF('P','mm','A4');

		$this->SetMargins(30,20,20);
		$this->SetAuthor(Constants::invoice_name);
		$this->SetCreator('BusinessAdmin Correspondence Generator');
		$this->SetDisplayMode('fullpage','continuous');
	}

	/**
	 * Workaround for euro signs
	 *
	 * Euro signs in FPDF should be chr(128). Other signs don't have to be changed.
	 *
	 * @return a valuta symbol that can be used in FPDF
	 */
	public static function valuta() {
		switch (Constants::invoice_valuta) {
			case '€':
				return chr(128);
			default:
				return Constants::invoice_valuta;
		}
	}

	/**
	 * Set the language of the correspondence (used to translate stuff)
	 *
	 * @param string $lang          The language, two letter code ('en', 'nl', ...)
	 */
	function SetLangauge($lang) {
		$supported = array('nl', 'en');
		if (!in_array($lang, $supported)) {
			throw new Exception("Language not supported");
		} else {
			$this->language = $lang;
		}
	}

	/**
	 * Set the contact to whom this correspondence will be sent (used for the address)
	 *
	 * @param contact $contact      The contact
	 */
	function SetContact($contact) {
		$this->contact = $contact;

		$this->language = $contact->language;
	}

	/**
	 * Makes a header with your details and the address of the contact
	 */
	function CorrespondenceHeader() {
		if (file_exists(Constants::files_folder . 'logo-correspondence.png')) {
			$this->Image(Constants::files_folder . 'logo-correspondence.png',30,20,50);
		}

		$this->SetFont('Helvetica','',7);
		$this->Cell(110,20);
		$this->Cell(12,1,' ','T');
		$this->Cell(2,1);
		$this->Cell(35,1,' ','T');
		$this->Ln();

		$this->Cell(110,3.5);
		$this->SetFont('','B');
		$this->Cell(12,3.5,$this->_('adres'),'',0,'R');
		$this->Cell(2,3.5);
		$this->SetFont('','');
		$this->Cell(35,3.5, Constants::invoice_name);
		$this->Ln();

		$this->Cell(124,3.5);
		$this->Cell(35,3.5, Constants::invoice_address_1);
		$this->Ln();
		$this->Cell(124,3.5);
		$this->Cell(35,3.5, Constants::invoice_address_2);
		$this->Ln();
		$this->Cell(124,3.5);
		$this->Cell(35,3.5, Constants::invoice_address_3);
		$this->Ln();
		$this->Cell(160,1.5);
		$this->Ln();
		$this->Cell(110,3.5);
		$this->SetFont('','B');
		$this->Cell(12,3.5,$this->_('btwnr'),'',0,'R');
		$this->Cell(2,3.5);
		$this->SetFont('','');
		$this->Cell(35,3.5, Constants::invoice_tax_nr);
		$this->Ln();
		$this->Cell(160,1.5);
		$this->Ln();
		$this->Cell(110,3.5);
		$this->SetFont('','B');
		$this->Cell(12,3.5, $this->_('iban'),'',0,'R');
		$this->Cell(2,3.5);
		$this->SetFont('','');
		$this->Cell(35,3.5, Constants::invoice_iban);
		$this->Ln();
		$this->Cell(160,1.5);
		$this->Ln();
		$this->Cell(110,3.5);
		$this->SetFont('','B');
		$this->Cell(12,3.5, $this->_('tel-nr'),'',0,'R');
		$this->Cell(2,3.5);
		$this->SetFont('','',7);
		$this->Cell(35,3.5, Constants::invoice_tel_nr);
		$this->Ln();
		$this->Cell(110,3.5);
		$this->SetFont('','B');
		$this->Cell(12,3.5, $this->_('email'),'',0,'R');
		$this->Cell(2,3.5);
		$this->SetFont('','');
		$this->Cell(35,3.5, Constants::invoice_email);
		$this->Ln();
		$this->Cell(110,1);
		$this->Cell(12,1,' ','B');
		$this->Cell(2,1);
		$this->Cell(35,1,' ','B');
		$this->Ln();
		$this->Cell(160,15);
		$this->Ln();

		$this->SetFont('','',11);
		$this->SetXY(30,56.5);
		$this->Cell(90,5.5,utf8_decode($this->contact->name));
		$this->Ln();
		$this->SetXY(30,61.5);
		$this->Cell(90,5.5,utf8_decode($this->contact->address));
		$this->Ln();
		$this->SetXY(30,66.5);
		$this->Cell(90,5.5,utf8_decode($this->contact->postal_code.' '.$this->contact->city));
		$this->Ln();
		$this->SetXY(30,71.5);
		$this->Cell(90,5.5,utf8_decode($this->contact->country));
		$this->Ln();
	}

	/**
	 * Put PDF information
	 */
	function _putinfo()
	{
		$this->_out('/Producer '.$this->_textstring('BusinessAdmin Correspondence Generator'));
		if(!empty($this->title))
			$this->_out('/Title '.$this->_textstring($this->title));
		if(!empty($this->subject))
			$this->_out('/Subject '.$this->_textstring($this->subject));
		if(!empty($this->author))
			$this->_out('/Author '.$this->_textstring($this->author));
		if(!empty($this->keywords))
			$this->_out('/Keywords '.$this->_textstring($this->keywords));
		if(!empty($this->creator))
			$this->_out('/Creator '.$this->_textstring($this->creator));
		$this->_out('/CreationDate '.$this->_textstring('D:'.@date('YmdHis')));
	}

	/**
	 * Have we reached the bottom of the page yet?
	 *
	 * @return bool
	 */
	public function endOfPage() {
		return ($this->GetY() > self::$page_height - self::$margin_bottom);
	}

	/**
	 * Start a new page if we're on the end
	 */
	public function addPageIfOnEnd() {
		if ($this->endOfPage()) {
			$this->Ln();
			$this->AddPage();
			$this->Cell(100, 5, ''); // blank line
			$this->Ln();
		}
	}
}