<?php

/**
 *
 * PHP Pro Bid $Id$ WdpA7GYUyKAazQ+ylMumSrEw2NrSq6I8545WR20o/6uePsPkriFe27vLNLvaIS0hfcJWOFGlmVF6N4FZnp45MA==
 *
 * @link        http://www.phpprobid.com
 * @copyright   Copyright (c) 2015 Online Ventures Software & CodeCube SRL
 * @license     http://www.phpprobid.com/license Commercial License
 *
 * @version     7.7
 */
/**
 * payment gateway model abstract class
 *
 * IMPORTANT: all methods that extend this class must have the name identical with the
 * 'name' field in the payment_gateways table.
 */

namespace Ppb\Model\PaymentGateway;

use Ppb\Db\Table\Row\AbstractRow,
    Cube\Controller\Request\AbstractRequest,
    Cube\Controller\Front,
    Cube\View,
    Ppb\Service;

abstract class AbstractPaymentGateway extends AbstractRow
{

    /**
     * constants that define the module/controller and actions for various urls that need to be generated by the
     * payment gateways models (ipn/success/failure)
     */
    const MODULE = 'app';
    const CONTROLLER = 'payment';
    const ACTION_COMPLETED = 'completed';
    const ACTION_FAILED = 'failed';
    const ACTION_IPN = 'ipn';

    /**
     *
     * payment gateway success url
     *
     * @var array
     */
    public static $successUrl = array(
        'module'     => self::MODULE,
        'controller' => self::CONTROLLER,
        'action'     => self::ACTION_COMPLETED
    );

    /**
     *
     * payment gateway failure url
     *
     * @var array
     */
    public static $failureUrl = array(
        'module'     => self::MODULE,
        'controller' => self::CONTROLLER,
        'action'     => self::ACTION_FAILED,
    );

    /**
     *
     * payment gateway ipn url
     *
     * @var array
     */
    public static $ipnUrl = array(
        'module'     => self::MODULE,
        'controller' => self::CONTROLLER,
        'action'     => self::ACTION_IPN,
        'gateway'    => null,
    );

    /**
     *
     * the name of the payment gateway
     *
     * @var string
     */
    protected $_gatewayName;
    /**
     *
     * transaction id, required by the payment form
     *
     * @var int
     */
    protected $_transactionId;

    /**
     *
     * name (description) of the payment
     * can be an array with text and args (for translation purposes)
     *
     * @var string|array
     */
    protected $_name;

    /**
     *
     * payment amount, required by the payment form
     *
     * @var float
     */
    protected $_amount;

    /**
     *
     * payment currency, required by the payment form
     *
     * @var string
     */
    protected $_currency;

    /**
     *
     * settings array
     *
     * @var array
     */
    protected $_settings;

    /**
     *
     * payment gateway description
     *
     * @var string
     */
    protected $_description;

    /**
     *
     * gateway payment status response, provided by the ipn
     *
     * @var string
     */
    protected $_gatewayPaymentStatus;

    /**
     *
     * gateway transaction code, provided by the ipn
     *
     * @var string
     */
    protected $_gatewayTransactionCode;

    /**
     *
     * view object
     *
     * @var \Cube\View
     */
    protected $_view;

    /**
     *
     * class constructor
     *
     * @param int $gatewayName gateway name
     * @param int $userId      user id, if we have a direct payment
     *
     * @throws \RuntimeException
     */
    public function __construct($gatewayName, $userId = null)
    {
        $gatewaysService = new Service\Table\PaymentGateways();
        $gateway = $gatewaysService->findBy('name', $gatewayName);

        if (!$gateway['id']) {
            $translate = $this->getTranslate();

            throw new \RuntimeException(
                sprintf($translate->_("The gateway you are trying to use, '%s', does not exist."), $gatewayName));
        }

        $this->setGatewayName($gatewayName);

        $data = array(
            'table' => $gatewaysService->getTable(),
            'data'  => $gatewaysService->getData($userId, $gateway['id'], false, true),
        );

        parent::__construct($data);

        $this->_settings = Front::getInstance()->getBootstrap()->getResource('settings');
    }

    /**
     *
     * set gateway name
     *
     * @param string $gatewayName
     *
     * @return $this
     */
    public function setGatewayName($gatewayName)
    {
        $this->_gatewayName = $gatewayName;

        return $this;
    }

    /**
     *
     * get gateway name
     *
     * @return string
     */
    public function getGatewayName()
    {
        return $this->_gatewayName;
    }


    /**
     *
     * get transaction id
     *
     * @return int
     */
    public function getTransactionId()
    {
        return intval($this->_transactionId);
    }

    /**
     *
     * set transaction id
     *
     * @param int $transactionId
     *
     * @return \Ppb\Model\PaymentGateway\AbstractPaymentGateway
     */
    public function setTransactionId($transactionId)
    {
        $this->_transactionId = $transactionId;

        return $this;
    }

    /**
     *
     * get name of transaction
     *
     * @return string
     */
    public function getName()
    {
        return $this->_name;
    }

    /**
     *
     * set name of transaction
     * can be a string or an array with "string" and "args" keys - used for translations
     *
     * @param string|array $name
     *
     * @throws \InvalidArgumentException
     * @return \Ppb\Model\PaymentGateway\AbstractPaymentGateway
     */
    public function setName($name)
    {
        $translate = $this->getTranslate();

        if (is_array($name)) {
            if (!array_key_exists('string', $name) && !array_key_exists('args', $name)) {
                throw new \InvalidArgumentException("The 'name' array must contain the 'string' and 'args' keys.");
            }

            $string = (null !== $translate) ? $translate->_($name['string']) : $name['string'];
            $name = vsprintf($string, $name['args']);
        }

        if (null !== $translate) {
            $name = $translate->_($name);
        }

        $this->_name = $name;

        return $this;
    }

    /**
     *
     * get transaction amount
     *
     * @return float
     */
    public function getAmount()
    {
        return $this->_amount;
    }

    /**
     *
     * set transaction amount
     * convert all amounts to a standard format (eg: 12000.00)
     *
     * @param string $amount
     *
     * @return \Ppb\Model\PaymentGateway\AbstractPaymentGateway
     */
    public function setAmount($amount)
    {

        $this->_amount = number_format($amount, 2, '.', '');

        return $this;
    }

    /**
     *
     * get transaction currency
     *
     * @return string
     */
    public function getCurrency()
    {
        return $this->_currency;
    }

    /**
     *
     * set transaction currency
     *
     * @param string $currency
     *
     * @return \Ppb\Model\PaymentGateway\AbstractPaymentGateway
     */
    public function setCurrency($currency)
    {
        $this->_currency = $currency;

        return $this;
    }

    /**
     *
     * get gateway description string
     *
     * @return string
     */
    public function getDescription()
    {
        $translate = $this->getTranslate();

        if (null !== $translate) {
            return $translate->_($this->_description);
        }

        return $this->_description;
    }

    /**
     *
     * set gateway description string
     *
     * @param string $description
     *
     * @return \Ppb\Model\PaymentGateway\AbstractPaymentGateway
     */
    public function setDescription($description)
    {
        $this->_description = (string)$description;

        return $this;
    }

    /**
     *
     * get gateway payment status response
     *
     * @return string
     */
    public function getGatewayPaymentStatus()
    {
        return $this->_gatewayPaymentStatus;
    }

    /**
     *
     * set gateway payment status response
     *
     * @param string $gatewayPaymentStatus
     *
     * @return \Ppb\Model\PaymentGateway\AbstractPaymentGateway
     */
    public function setGatewayPaymentStatus($gatewayPaymentStatus)
    {
        $this->_gatewayPaymentStatus = (string)$gatewayPaymentStatus;

        return $this;
    }

    /**
     *
     * get gateway transaction code (id), provided by the ipn
     *
     * @return string
     */
    public function getGatewayTransactionCode()
    {
        return $this->_gatewayTransactionCode;
    }

    /**
     *
     * set gateway transaction code (id)
     *
     * @param string $gatewayTransactionCode
     *
     * @return \Ppb\Model\PaymentGateway\AbstractPaymentGateway
     */
    public function setGatewayTransactionCode($gatewayTransactionCode)
    {
        $this->_gatewayTransactionCode = (string)$gatewayTransactionCode;

        return $this;
    }


    /**
     *
     * get view object
     *
     * @return \Cube\View
     */
    public function getView()
    {
        if (!$this->_view instanceof View) {
            $this->setView(
                Front::getInstance()->getBootstrap()->getResource('view'));
        }

        return $this->_view;
    }

    /**
     *
     * set view object
     *
     * @param \Cube\View $view
     *
     * @return $this
     */
    public function setView(View $view)
    {
        $this->_view = $view;

        return $this;
    }

    /**
     *
     * get form elements, used to create the form needed to add the gateway settings
     *
     * @return array
     */
    public function getElements()
    {
        return array();
    }

    /**
     *
     * prepare and return ipn url
     *
     * @return string
     */
    public function getIpnUrl()
    {
        $params = self::$ipnUrl;
        $params['gateway'] = strtolower($this->getGatewayName());

        return $this->getView()->url($params);
    }

    /**
     *
     * prepare and return payment success url
     *
     * @return string
     */
    public function getSuccessUrl()
    {
        $params = self::$successUrl;
        if ($this->_transactionId) {
            $params['transaction_id'] = $this->_transactionId;
        }

        return $this->getView()->url($params);
    }

    /**
     *
     * prepare and return payment failed url
     *
     * @return string
     */
    public function getFailureUrl()
    {
        $params = self::$failureUrl;
        if ($this->_transactionId) {
            $params['transaction_id'] = $this->_transactionId;
        }

        return $this->getView()->url($params);
    }

    /**
     *
     * method that checks if the amount and currency submitted through an ipn is the
     * coincides with the row in the transactions table
     *
     * @param float  $amount
     * @param string $currency
     *
     * @return bool
     */
    public function checkIpnAmount($amount, $currency)
    {
        if ($this->_amount == $amount && $this->_currency == $currency) {
            return true;
        }

        return false;
    }

    /**
     *
     * shorten a string that exceeds the maximum allowed number of chars
     *
     * @param string $string
     * @param int    $maxChars
     * @param string $replace
     *
     * @return string
     */
    protected function _shortenString($string, $maxChars, $replace = '...')
    {
        if (strlen($string) > $maxChars) {
            $maxChars -= strlen($replace);
            $string = substr($string, 0, $maxChars) . $replace;
        }

        return $string;
    }

    /**
     *
     * dummy function used as a placeholder for translatable sentences
     *
     * @param $string
     *
     * @return string
     */
    protected function _($string)
    {
        return $string;
    }

    /**
     *
     * check if the gateway is enabled
     */
    abstract public function enabled();

    /**
     *
     * form elements needed to create the payment form
     */
    abstract public function formElements();

    /**
     *
     * get the post url of the gateway form
     */
    abstract public function getPostUrl();

    /**
     *
     * @param \Cube\Controller\Request\AbstractRequest $request
     */
    abstract public function processIpn(AbstractRequest $request);
}

