Service BetAndWin

<?php
/**
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 *
 * Encoding: UTF-8
 *
 * @package CesarEngineExample\Normalizer
 * @author Cesar Romero - 2015-10-15 11:02:37
 */

namespace CesarEngineExample\Normalizer;

use CesarEngineExample\Entity\Player;
use CesarEngineExample\Entity\PlayerToken;
use CesarEngineExample\Entity\Transaction;
use CesarEngineExample\Normalizer\Exception\NormalizerException;
use Cesar\Mvc\RepositoryLocator;

/**
 * BetAndWin class for the normalizer, it's meant to translate any provider betAndWin transaction into the common
 * API betAndWin. It uses the common methods of it's abstract class.
 *
 * @package CesarEngineExample\Normalizer
 *
 * @author César Romero <cesar.romero@Cesar.com>
 * @since 20 Jan 2016
 * @see Please notify modifications here with a @modified tag, ain't much cost but it'll help you maintain this
 * beauty I have given you 🙂
 */
class BetAndWin extends AbstractNormalizer
{
    /**
     * The method we are calling to the merchant
     *
     * @var string
     */
    protected $method = 'BetAndWin';

    /**
     * Expected parameters for the request
     *
     * @var array
     */
    protected $requestParams = array(
        'userId',
        'token',
        'updateToken',
        'timestamp',
        'betAmountReal',
        'betAmountBonus',
        'winAmountReal',
        'winAmountBonus',
        'transactionId',
        'roundId',
        'gameId',
    );

    /**
     * Expected parameters for the response
     *
     * @var array
     */
    protected $responseParams = array(
        'balanceReal',
        'balanceBonus',
        'merchantTransactionId',
        'alreadyProcessed',
        'token',
    );

    /**
     * BetAndWin constructor:
     *
     * This method does all:
     *
     * Set's into the class and parent class all the necessary information.
     * It will also check that the parameters are the ones that should be.
     *
     * Then it will call the merchant and parse the response.
     *
     * Finally it analyses the response and checks that it's correct or not. It's important that it marks the
     * transaction as TRUE or FALSE so we know if the casino accepted it or not.
     *
     * @param \CesarEngineExample\Entity\Player $player
     * @param \CesarEngineExample\Entity\PlayerToken $playerToken
     * @param \CesarEngineExample\Entity\Transaction $transaction
     * @param \CesarEngineExample\Entity\PlayerToken|null $updateToken
     */
    public function __construct(
        Player $player,
        PlayerToken $playerToken,
        Transaction $transaction,
        PlayerToken $updateToken = null
    ) {
        /** @var \CesarEngineExample\Repository\MerchantAttribute $merchantAttributeRepository */
        $merchantAttributeRepository = RepositoryLocator::getRepository('MerchantAttribute');

        //POPULATE THE INFORMATION
        $this->setTransaction($transaction);
        $this->setMerchantAttributes(
            $merchantAttributeRepository->getMerchantAttributesByMerchantId($player->getMerchantId())
        );
        $this->setPlayer($player);
        $this->setPlayerToken($playerToken);
        $this->setUpdatePlayerToken($updateToken);

        //SET THE METHOD
        $this->setMethod($this->method);

        //SET THE DATA TO CALL THE MERCHANT
        $this->setData(array(
            'userId' => $this->getPlayer()->getUserId(),
            'token' => $this->getPlayerToken()->getToken(),
            'updateToken' => (is_object($this->getUpdatePlayerToken()))
                ? $this->getUpdatePlayerToken()->getToken() : null,
            'timestamp' => time(),
            'betAmountReal' => $transaction->getBetAmountReal(),
            'betAmountBonus' => $transaction->getBetAmountBonus(),
            'winAmountReal' => $transaction->getWinAmountReal(),
            'winAmountBonus' => $transaction->getWinAmountBonus(),
            'transactionId' => $transaction->getExternalTransactionId(),
            'roundId' => preg_replace("#[^0-9]#", '', $transaction->getExternalRoundId()),
            'gameId' => $this->getGameConfiguration()->getGameId(),
        ));

        //VERIFY REQUEST AND RESPONSE
        $this->checkRequestParameters();
        $this->callMerchant();
        $this->checkResponseParameters();

        //UPDATE THE TRANSACTION AND MARK AS SUCCESS
        $transaction->setMerchantTransactionId($this->getResponseParam('merchantTransactionId'));
        $transaction->setModifiedBalance(!$this->getAlreadyProcessed());
        $transaction->setSuccess(true);
        $transaction->save();
    }

    /**
     * Check that the parameters we send to the merchant are the minimum required
     *
     * @throws \CesarEngineExample\Normalizer\Exception\NormalizerException
     */
    public function checkRequestParameters()
    {
        foreach ($this->requestParams as $param)
        {
            if (!array_key_exists($param, $this->getData()))
                throw new NormalizerException('Missing BetAndWin request parameter', 501);
        }
    }

    /**
     * Check that we got back the expected parameters from the merchant
     *
     * @throws \CesarEngineExample\Normalizer\Exception\NormalizerException
     */
    public function checkResponseParameters()
    {
        $error = $this->getResponseParam('errorCode');
        if (isset($error) && '' !== $error) {
            // mapping between merchantError and NormalizerError
            $merchantErrorMapping = array(
                0 => 506,
                1 => 506,
                2 => 505,
                3 => 503,
                4 => 504,
            );

            if (array_key_exists($error, $merchantErrorMapping))
                throw new NormalizerException(
                    NormalizerException::$exceptions[$merchantErrorMapping[$error]],
                    $merchantErrorMapping[$error]
                );
            else
                throw new NormalizerException(NormalizerException::$exceptions[5], 5);
        }

        foreach ($this->responseParams as $param)
        {
            if (!array_key_exists($param, $this->getResponse()))
                throw new NormalizerException('Missing BetAndWin response parameter', 502);
        }
    }

    /**
     * Get the total balance of the player
     *
     * @return float
     */
    public function getBalanceTotal()
    {
        return $this->getResponseParam('balanceReal') + $this->getResponseParam('balanceBonus');
    }

    /**
     * Get the real balance of the player
     *
     * @return float
     */
    public function getBalanceReal()
    {
        return $this->getResponseParam('balanceReal');
    }

    /**
     * Get the bonus balance of the player
     *
     * @return float
     */
    public function getBalanceBonus()
    {
        return $this->getResponseParam('balanceBonus');
    }

    /**
     * Get the merchant transactionId
     *
     * @return string
     */
    public function getMerchantTransactionId()
    {
        return $this->getResponseParam('merchantTransactionId');
    }

    /**
     * Get the information of the status of the trx and check if it was already processed
     *
     * @return boolean
     */
    public function getAlreadyProcessed()
    {
        if ($this->response['alreadyProcessed'] === true || $this->response['alreadyProcessed'] == 'true')
            return true;
        return false;
    }
}